summaryrefslogtreecommitdiffstats
path: root/tools/src/h5repack/h5repack.h
blob: 0252768e83b8e9911f64f9c907cc87db62fd1fb5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by The HDF Group.                                               *
 * Copyright by the Board of Trustees of the University of Illinois.         *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
 * terms governing use, modification, and redistribution, is contained in    *
 * the COPYING file, which can be found at the root of the source code       *
 * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases.  *
 * If you do not have access to either file, you may request a copy from     *
 * help@hdfgroup.org.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */


#ifndef H5REPACK_H__
#define H5REPACK_H__

#include "H5private.h"
#include "hdf5.h"
#include "h5trav.h"

#define H5FOPENERROR "unable to open file"
#define PFORMAT  "%-7s %-7s %-7s\n"   /* chunk info, compression info, name*/
#define PFORMAT1 "%-7s %-7s %-7s"     /* chunk info, compression info, name*/
#define MAX_NC_NAME 256               /* max length of a name */
#define MAX_VAR_DIMS 32               /* max per variable dimensions */
#define FORMAT_OBJ      " %-27s %s\n"   /* obj type, name */
#define FORMAT_OBJ_ATTR "  %-27s %s\n"  /* obj type, name */
#define MAX_COMPACT_DSIZE  64512  /* max data size for compact layout. -1k for header size */

/* File space default information */
#define FS_PAGESIZE_DEF            4096
#define FS_STRATEGY_DEF            H5F_FSPACE_STRATEGY_FSM_AGGR
#define FS_PERSIST_DEF             FALSE
#define FS_THRESHOLD_DEF           1


/*-------------------------------------------------------------------------
 * data structures for command line options
 *-------------------------------------------------------------------------
 */

/* a list of names */
typedef struct {
    char         obj[MAX_NC_NAME];
} obj_list_t;

/*
 the type of filter and additional parameter
 type can be one of the filters
 H5Z_FILTER_NONE        0,  uncompress if compressed
 H5Z_FILTER_DEFLATE     1 , deflation like gzip
 H5Z_FILTER_SHUFFLE     2 , shuffle the data
 H5Z_FILTER_FLETCHER32  3 , letcher32 checksum of EDC
 H5Z_FILTER_SZIP        4 , szip compression
 H5Z_FILTER_NBIT        5 , nbit compression
 H5Z_FILTER_SCALEOFFSET 6 , scaleoffset compression
*/

#define CD_VALUES 20

typedef struct {
    H5Z_filter_t filtn;                           /* filter identification number */
    unsigned     filt_flag;                       /* filter definition flag */
    unsigned     cd_values[CD_VALUES];            /* filter client data values */
    size_t       cd_nelmts;                       /* filter client number of values */
} filter_info_t;

/* chunk lengths along each dimension and rank */
typedef struct {
    hsize_t      chunk_lengths[MAX_VAR_DIMS];
    int          rank;
} chunk_info_t;

/* we currently define a maximum value for the filters array,
   that corresponds to the current library filters */
#define H5_REPACK_MAX_NFILTERS 6

/* information for one object, contains PATH, CHUNK info and FILTER info */
typedef struct {
    char          path[MAX_NC_NAME];               /* name of object */
    filter_info_t filter[H5_REPACK_MAX_NFILTERS];  /* filter array */
    int           nfilters;                        /* current number of filters */
    H5D_layout_t  layout;                          /* layout information */
    chunk_info_t  chunk;                           /* chunk information */
    hid_t         refobj_id;                       /* object ID, references */
} pack_info_t;

/* store a table of all objects */
typedef struct {
    unsigned int  size;
    unsigned int  nelems;
    pack_info_t   *objs;
} pack_opttbl_t;


/*-------------------------------------------------------------------------
 * command line options
 *-------------------------------------------------------------------------
 */

/* all the above, ready to go to the hrepack call */
typedef struct {
    pack_opttbl_t   *op_tbl;     /*table with all -c and -f options */
    int             all_layout;  /*apply the layout to all objects */
    int             all_filter;  /*apply the filter to all objects */
    filter_info_t   filter_g[H5_REPACK_MAX_NFILTERS];    /*global filter array for the ALL case */
    int             n_filter_g;  /*number of global filters */
    chunk_info_t    chunk_g;     /*global chunk INFO for the ALL case */
    H5D_layout_t    layout_g;    /*global layout information for the ALL case */
    int             verbose;     /*verbose mode */
    hsize_t         min_comp;    /*minimum size to compress, in bytes */
    int             use_native;  /*use a native type in write */
    hbool_t         latest;      /*pack file with the latest file format */
    int             grp_compact; /* Set the maximum number of links to store as header messages in the group */
    int             grp_indexed; /* Set the minimum number of links to store in the indexed format */
    int             msg_size[8]; /* Minimum size of shared messages: dataspace,
                                    datatype, fill value, filter pipleline, attribute */
    const char      *ublock_filename;  /* user block file name */
    hsize_t         ublock_size;       /* user block size */
    hsize_t         meta_block_size;   /* metadata aggregation block size (for H5Pset_meta_block_size) */
    hsize_t         threshold;         /* alignment threshold for H5Pset_alignment */
    hsize_t         alignment;         /* alignment for H5Pset_alignment */
    H5F_fspace_strategy_t fs_strategy; /* File space handling strategy */
    int             fs_persist;        /* Free space section threshold */
    long            fs_threshold;      /* Free space section threshold */
    long long       fs_pagesize;       /* File space page size */
} pack_opt_t;


typedef struct named_dt_t {
    haddr_t             addr_in;    /* Address of the named dtype in the in file */
    hid_t               id_out;     /* Open identifier for the dtype in the out file */
    struct named_dt_t   *next;      /* Next dtype */
} named_dt_t;

/*-------------------------------------------------------------------------
 * public functions
 *-------------------------------------------------------------------------
 */

#ifdef __cplusplus
extern "C" {
#endif

int h5repack(const char* infile, const char* outfile, pack_opt_t *options);
int h5repack_addfilter(const char* str, pack_opt_t *options);
int h5repack_addlayout(const char* str, pack_opt_t *options);
int h5repack_init(pack_opt_t *options, int verbose, hbool_t latest);
int h5repack_end(pack_opt_t *options);
int h5repack_verify(const char *in_fname, const char *out_fname, pack_opt_t *options);
int h5repack_cmp_pl(const char *fname1, const char *fname2);

/* Note: The below copy_named_datatype(), named_datatype_free(), copy_attr()
 * and struct named_dt_t were located in h5repack_copy.c as static prior to
 * bugfix1726.
 * Made shared functions as copy_attr() was needed in h5repack_refs.c.
 * However copy_attr() may be obsoleted when H5Acopy is available and put back
 * others to static in h5repack_copy.c.
 */
hid_t copy_named_datatype(hid_t type_in, hid_t fidout, named_dt_t **named_dt_head_p, trav_table_t *travt, pack_opt_t *options);
int named_datatype_free(named_dt_t **named_dt_head_p, int ignore_err);
int copy_attr(hid_t loc_in, hid_t loc_out, named_dt_t **named_dt_head_p,
              trav_table_t *travt, pack_opt_t *options);

#ifdef __cplusplus
}
#endif



/*-------------------------------------------------------------------------
 * private functions
 *-------------------------------------------------------------------------
 */


/*-------------------------------------------------------------------------
 * copy module
 *-------------------------------------------------------------------------
 */

int copy_objects   (const char* fnamein,
                    const char* fnameout,
                    pack_opt_t *options);

int do_copy_refobjs(hid_t fidin,
                    hid_t fidout,
                    trav_table_t *travt,
                    pack_opt_t *options);

/*-------------------------------------------------------------------------
 * filters and verify module
 *-------------------------------------------------------------------------
 */
void init_packobject(pack_info_t *obj);


/*-------------------------------------------------------------------------
 * filters and copy module
 *-------------------------------------------------------------------------
 */

int apply_filters(const char* name,    /* object name from traverse list */
                  int rank,            /* rank of dataset */
                  hsize_t *dims,       /* dimensions of dataset */
                  size_t msize,        /* size of type */
                  hid_t dcpl_id,       /* dataset creation property list */
                  pack_opt_t *options, /* repack options */
                  int *has_filter);    /* (OUT) object NAME has a filter */


/*-------------------------------------------------------------------------
 * options table
 *-------------------------------------------------------------------------
 */
int          options_table_init(pack_opttbl_t **tbl);
int          options_table_free(pack_opttbl_t *table);
int          options_add_layout(obj_list_t *obj_list,
                                unsigned n_objs,
                                pack_info_t *pack,
                                pack_opttbl_t *table);
int          options_add_filter(obj_list_t *obj_list,
                                unsigned n_objs,
                                filter_info_t filt,
                                pack_opttbl_t *table);
pack_info_t* options_get_object(const char *path,
                                pack_opttbl_t *table);

/*-------------------------------------------------------------------------
 * parse functions
 *-------------------------------------------------------------------------
 */

obj_list_t* parse_filter(const char *str,
                         unsigned *n_objs,
                         filter_info_t *filt,
                         pack_opt_t *options,
                         int *is_glb);

obj_list_t* parse_layout(const char *str,
                         unsigned *n_objs,
                         pack_info_t *pack,    /* info about object */
                         pack_opt_t *options);




#endif  /* H5REPACK_H__ */

n1010' href='#n1010'>1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by the Board of Trustees of the University of Illinois.         *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
 * terms governing use, modification, and redistribution, is contained in    *
 * the files COPYING and Copyright.html.  COPYING can be found at the root   *
 * of the source code distribution tree; Copyright.html can be found at the  *
 * root level of an installed copy of the electronic HDF5 document set and   *
 * is linked from the top-level documents page.  It can also be found at     *
 * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html.  If you do not have     *
 * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/*
 * Programmer:	Quincey Koziol <koziol@hdfgroup.org>
 *              Monday, July 31, 2006
 *
 * Purpose:	Free space tracking functions.
 *
 */

/****************/
/* Module Setup */
/****************/

#define H5FS_PACKAGE		/*suppress error about including H5FSpkg  */

/***********/
/* Headers */
/***********/
#include "H5private.h"		/* Generic Functions			*/
#include "H5Eprivate.h"		/* Error handling		  	*/
#include "H5FSpkg.h"		/* File free space			*/
#include "H5MFprivate.h"	/* File memory management		*/
#include "H5Vprivate.h"		/* Vectors and arrays 			*/

/****************/
/* Local Macros */
/****************/

/* Default starting size of section buffer */
#define H5FS_SINFO_SIZE_DEFAULT  64

/* Max. height of the skip list holding free list nodes */
#define H5FS_DEFAULT_SKIPLIST_HEIGHT     16


/******************/
/* 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(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace,
    const H5FS_section_class_t *cls, unsigned flags);
static herr_t H5FS_sect_decrease(H5F_t *f, hid_t dxpl_id, 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(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace,
    const H5FS_section_class_t *cls, 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(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace,
    const H5FS_section_class_t *cls, H5FS_section_info_t *sect, unsigned flags);
static herr_t H5FS_sect_link(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace,
    H5FS_section_info_t *sect, unsigned flags);
static herr_t H5FS_sect_merge(H5F_t *f, hid_t dxpl_id, 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(H5F_t *f, hid_t dxpl_id, 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;    /* Return value */

    FUNC_ENTER_NOAPI_NOINIT(H5FS_sinfo_new)

    /* Check arguments. */
    HDassert(f);
    HDassert(fspace);

    /* 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 = H5V_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 = (H5V_log2_gen(fspace->max_sect_size) + 7) / 8;
    sinfo->fspace = fspace;
#ifdef QAK
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 /* QAK */

    /* 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")

    /* Set return value */
    ret_value = sinfo;

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* H5FS_sinfo_new() */


/*-------------------------------------------------------------------------
 * Function:	H5FS_sinfo_pin
 *
 * Purpose:	Pin the section info for the free space manager in memory
 *              Either loads section info from disk, or creates new section info
 *
 * Return:	Success:	non-NULL, pointer to section info struct
 *		Failure:	NULL
 *
 * Programmer:	Quincey Koziol
 *              Monday, July 31, 2006
 *
 *-------------------------------------------------------------------------
 */
static H5FS_sinfo_t *
H5FS_sinfo_pin(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace)
{
    H5FS_sinfo_t *sinfo;        /* Section information struct created */
    H5FS_sinfo_t *ret_value;    /* Return value */

    FUNC_ENTER_NOAPI_NOINIT(H5FS_sinfo_pin)

    /* Check arguments. */
    HDassert(f);
    HDassert(fspace);

    /* Create new section info, if it doesn't exist yet */
    if(!H5F_addr_defined(fspace->sect_addr)) {
        /* 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 == (sinfo = H5FS_sinfo_new(f, fspace)))
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTCREATE, NULL, "can't create section info")

        /* Allocate space for the section info */
        fspace->sect_size = H5FS_SINFO_SIZE_DEFAULT;
        fspace->alloc_sect_size = (size_t)fspace->sect_size;
        if(HADDR_UNDEF == (fspace->sect_addr = H5MF_alloc(f, H5FD_MEM_FSPACE_SINFO, dxpl_id, fspace->alloc_sect_size)))
            HGOTO_ERROR(H5E_STORAGE, H5E_NOSPACE, NULL, "file allocation failed for free space sections")

        /* Cache the new free space section info (pinned) */
        if(H5AC_set(f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, sinfo, H5AC__PIN_ENTRY_FLAG) < 0)
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTINIT, NULL, "can't add free space sections to cache")

        /* Mark free space header as dirty */
        if(H5AC_mark_pinned_or_protected_entry_dirty(f, fspace) < 0)
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, NULL, "unable to mark free space header as dirty")
    } /* end if */
    else {
#ifdef QAK
HDfprintf(stderr, "%s: Reading in existing sections, fspace->sect_addr = %a\n", FUNC, fspace->sect_addr);
#endif /* QAK */
        /* Protect the free space sections */
        if(NULL == (sinfo = H5AC_protect(f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, NULL, fspace, H5AC_WRITE)))
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTPROTECT, NULL, "unable to load free space sections")

        /* Pin them in the cache */
        if(H5AC_pin_protected_entry(f, sinfo) < 0)
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTPIN, NULL, "unable to pin free space sections")

        /* Unlock free space sections, now pinned */
        if(H5AC_unprotect(f, dxpl_id, H5AC_FSPACE_SINFO, fspace->sect_addr, sinfo, H5AC__NO_FLAGS_SET) < 0)
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTUNPROTECT, NULL, "unable to release free space sections")
    } /* end else */
#ifdef QAK
HDfprintf(stderr, "%s: sinfo->serial_size_count = %Zu\n", FUNC, sinfo->serial_size_count);
#endif /* QAK */

    /* Update pointer to free space header for section info */
    sinfo->fspace = fspace;

    /* Set return value */
    ret_value = sinfo;

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* H5FS_sinfo_pin() */


/*-------------------------------------------------------------------------
 * Function:	H5FS_sect_increase
 *
 * Purpose:	Increase the size of the serialized free space section info
 *              on disk
 *
 * Return:	Success:	non-negative
 *
 *		Failure:	negative
 *
 * Programmer:	Quincey Koziol
 *              Monday, May  8, 2006
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5FS_sect_increase(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace,
    const H5FS_section_class_t *cls, unsigned flags)
{
    herr_t ret_value = SUCCEED;         /* Return value */

    FUNC_ENTER_NOAPI_NOINIT(H5FS_sect_increase)

    /* 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, 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(f, dxpl_id, fspace) < 0)
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTCOMPUTE, FAIL, "can't adjust free space section size on disk")
        } /* end if */
    } /* end else */

    /* Mark free space header as dirty */
    if(H5AC_mark_pinned_or_protected_entry_dirty(f, fspace) < 0)
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty")

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:	Success:	non-negative
 *
 *		Failure:	negative
 *
 * Programmer:	Quincey Koziol
 *              Monday, May  8, 2006
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5FS_sect_decrease(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace, const H5FS_section_class_t *cls)
{
    herr_t ret_value = SUCCEED;         /* Return value */

    FUNC_ENTER_NOAPI_NOINIT(H5FS_sect_decrease)

    /* 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->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(f, dxpl_id, fspace) < 0)
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTCOMPUTE, FAIL, "can't adjust free space section size on disk")
    } /* end else */

    /* Mark free space header as dirty */
    if(H5AC_mark_pinned_or_protected_entry_dirty(f, fspace) < 0)
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty")

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:	Success:	non-negative
 *		Failure:	negative
 *
 * 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(H5FS_size_node_decr)

    /* 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 = 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 */
        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:	Success:	non-negative
 *		Failure:	negative
 *
 * 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(H5FS_sect_unlink_size)

    /* 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 = H5V_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 = 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 = 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:	Success:	non-negative
 *
 *		Failure:	negative
 *
 * Programmer:	Quincey Koziol
 *              Wednesday, May 17, 2006
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5FS_sect_unlink_rest(H5F_t *f, hid_t dxpl_id, 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(H5FS_sect_unlink_rest)

    /* Check arguments. */
    HDassert(f);
    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 = 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(f, dxpl_id, 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;

    /* Mark free space sections as changed */
    if(H5AC_mark_pinned_or_protected_entry_dirty(f, fspace->sinfo) < 0)
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space sections as dirty")

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* H5FS_sect_unlink_rest() */


/*-------------------------------------------------------------------------
 * Function:	H5FS_sect_remove
 *
 * Purpose:	Remove a section from the free space manager
 *
 * Return:	Success:	non-negative
 *		Failure:	negative
 *
 * 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)
{
    const H5FS_section_class_t *cls;    /* Class of section */
    herr_t ret_value = SUCCEED;         /* Return value */

    FUNC_ENTER_NOAPI_NOINIT(H5FS_sect_remove)

    /* Check arguments. */
    HDassert(f);
    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(f, dxpl_id, 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() */


/*-------------------------------------------------------------------------
 * Function:	H5FS_sect_link_size
 *
 * Purpose:	Add a section of free space to the free list bins
 *
 * Return:	Success:	non-negative
 *		Failure:	negative
 *
 * 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 */
    unsigned bin;                       /* Bin to put the free space section in */
    herr_t ret_value = SUCCEED;         /* Return value */

    FUNC_ENTER_NOAPI_NOINIT(H5FS_sect_link_size)
#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 = H5V_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, 0.5, (size_t)H5FS_DEFAULT_SKIPLIST_HEIGHT)))
            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 = 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")

        /* 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, 0.5, (size_t)H5FS_DEFAULT_SKIPLIST_HEIGHT)))
            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")

        /* 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:
    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:	Success:	non-negative
 *
 *		Failure:	negative
 *
 * Programmer:	Quincey Koziol
 *              Wednesday, May 17, 2006
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5FS_sect_link_rest(H5F_t *f, hid_t dxpl_id, 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(H5FS_sect_link_rest)

    /* Check arguments. */
    HDassert(f);
    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, 0.5, (size_t)H5FS_DEFAULT_SKIPLIST_HEIGHT)))
                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(f, dxpl_id, 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:	Success:	non-negative
 *
 *		Failure:	negative
 *
 * Programmer:	Quincey Koziol
 *              Wednesday, May 17, 2006
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5FS_sect_link(H5F_t *f, hid_t dxpl_id, 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(H5FS_sect_link)

    /* Check arguments. */
    HDassert(f);
    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(f, dxpl_id, 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:	Success:	non-negative
 *
 *		Failure:	negative
 *
 * Programmer:	Quincey Koziol
 *              Wednesday, May 17, 2006
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5FS_sect_merge(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace,
    H5FS_section_info_t **sect, void *op_data)
{
    H5FS_section_class_t *sect_cls;     /* Section's class */
    H5FS_section_info_t *tmp_sect_node; /* Temporary free space section */
    hbool_t modified;                   /* Flag to indicate merge or shrink occurred */
    htri_t status;                      /* Status value */
    herr_t ret_value = SUCCEED;         /* Return value */

    FUNC_ENTER_NOAPI_NOINIT(H5FS_sect_merge)

    /* 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 {
            H5FS_section_class_t *tmp_sect_cls;     /* Temporary section's class */

            /* Reset 'modification occurred' flag */
            modified = FALSE;

            /* Look for neighboring section before new section */
            tmp_sect_node = H5SL_less(fspace->sinfo->merge_list, &(*sect)->addr);

            /* Check for node before new node able to merge with new node */
            if(tmp_sect_node) {
                /* Get classes for right & left sections */
                tmp_sect_cls = &fspace->sect_cls[tmp_sect_node->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_node->type == (*sect)->type))
                        && tmp_sect_cls->can_merge) {
                    /* Determine if the sections can merge */
                    if((status = (*tmp_sect_cls->can_merge)(tmp_sect_node, *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(f, dxpl_id, fspace, tmp_sect_node) < 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_node, *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_node;

                        /* Indicate successful merge occurred */
                        modified = TRUE;
                    } /* end if */
                } /* end if */
            } /* end if */

            /* Look for section after new (or merged) section */
            tmp_sect_node = H5SL_greater(fspace->sinfo->merge_list, &(*sect)->addr);

            /* Check for node after new node able to merge with new node */
            if(tmp_sect_node) {
                /* Get classes for right & left sections */
                sect_cls = &fspace->sect_cls[(*sect)->type];
                tmp_sect_cls = &fspace->sect_cls[tmp_sect_node->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_node->type))
                        && sect_cls->can_merge) {

                    /* Determine if the sections can merge */
                    if((status = (*sect_cls->can_merge)(*sect, tmp_sect_node, 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(f, dxpl_id, fspace, tmp_sect_node) < 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_node, op_data) < 0)
                            HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't merge two sections")

                        /* 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 */
                /* Look for neighboring section before new section */
                if(fspace->sinfo->merge_list) {
                    tmp_sect_node = H5SL_less(fspace->sinfo->merge_list, &(*sect)->addr);

                    /* Make certain there isn't a section after the new section */
                    HDassert(H5SL_greater(fspace->sinfo->merge_list, &(*sect)->addr) == NULL);
                } /* end if */
                else
                    tmp_sect_node = NULL;

                /* 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")

                /* Check if the new section was removed */
                if(*sect == NULL && tmp_sect_node) {
                    /* Remove 'less than' node from data structures */
                    if(H5FS_sect_remove(f, dxpl_id, fspace, tmp_sect_node) < 0)
                        HGOTO_ERROR(H5E_FSPACE, H5E_CANTRELEASE, FAIL, "can't remove section from internal data structures")

                    *sect = tmp_sect_node;
                } /* end if */

                /* Indicate successful merge occurred */
                modified = TRUE;
            } /* end if */
        } /* end if */
    } while(modified && *sect);
#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:	Success:	non-negative
 *
 *		Failure:	negative
 *
 * 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 */
    herr_t ret_value = SUCCEED;         /* Return value */

    FUNC_ENTER_NOAPI(H5FS_sect_add, FAIL)

#ifdef QAK
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 /* QAK */

    /* Check arguments. */
    HDassert(fspace);
    HDassert(sect);
    HDassert(H5F_addr_defined(sect->addr));
    HDassert(sect->size);

    /* Check if we need to go get the sections */
    if(fspace->sinfo == NULL) {
        if(NULL == (fspace->sinfo = H5FS_sinfo_pin(f, dxpl_id, fspace)))
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTDECODE, FAIL, "can't pin sections")
    } /* end if */

    /* 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 QAK
HDfprintf(stderr, "%s: Returning space\n", FUNC);
#endif /* QAK */

        /* Attempt to merge returned section with existing sections */
        if(H5FS_sect_merge(f, dxpl_id, 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(f, dxpl_id, fspace, sect, flags) < 0)
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, FAIL, "can't insert free space section into skip list")

#ifdef QAK
HDfprintf(stderr, "%s: fspace->hdr->tot_space = %Hu\n", FUNC, fspace->hdr->tot_space);
#endif /* QAK */
    /* Mark free space sections as changed */
    /* (if adding sections while deserializing sections, don't set the flag) */
    if(!(flags & H5FS_ADD_DESERIALIZING)) {
        if(H5AC_mark_pinned_or_protected_entry_dirty(f, fspace->sinfo) < 0)
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space sections as dirty")
    } /* end if */

done:
#ifdef H5FS_DEBUG
if(!(flags & (H5FS_ADD_DESERIALIZING | H5FS_ADD_SKIP_VALID)))
    H5FS_assert(fspace);
#endif /* H5FS_DEBUG */
    FUNC_LEAVE_NOAPI(ret_value)
} /* H5FS_sect_add() */


/*-------------------------------------------------------------------------
 * 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:	Success:	non-negative
 *
 *		Failure:	negative
 *
 * 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 */

    FUNC_ENTER_NOAPI_NOINIT(H5FS_sect_find_node)

    /* 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 = H5V_log2_gen(request);
    HDassert(bin < fspace->sinfo->nbins);
    while(bin < fspace->sinfo->nbins && fspace->sinfo->bins[bin].bin_list == NULL)
        bin++;

    /* 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)
     */
#ifdef QAK
HDfprintf(stderr, "%s: fspace->sinfo->nbins = %u\n", FUNC, fspace->sinfo->nbins);
HDfprintf(stderr, "%s: bin = %u\n", FUNC, bin);
#endif /* QAK */
    if(bin < fspace->sinfo->nbins)
        do {
            /* Look for large enough free space section in this bin */
            if(fspace->sinfo->bins[bin].bin_list)
                /* Check for large enough list of sections on list */
                if((fspace_node = H5SL_greater(fspace->sinfo->bins[bin].bin_list, &request))) {
                    const H5FS_section_class_t *cls;    /* Class of section */

                    /* Take first node off of the list (ie. node w/lowest address) */
                    if(NULL == (*node = 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")

                    /* Indicate that we found a node for the request */
                    HGOTO_DONE(TRUE)
                } /* end if */

            /* 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:	Success:	non-negative
 *
 *		Failure:	negative
 *
 * 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)
{
    htri_t ret_value = FALSE;           /* Return value */

    FUNC_ENTER_NOAPI(H5FS_sect_find, FAIL)

#ifdef QAK
HDfprintf(stderr, "%s: request = %Hu\n", FUNC, request);
#endif /* QAK */

    /* Check arguments. */
    HDassert(fspace);
    HDassert(request);
    HDassert(node);

    /* Check if we need to go get the sections */
    if(fspace->sinfo == NULL) {
        if(NULL == (fspace->sinfo = H5FS_sinfo_pin(f, dxpl_id, fspace)))
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTDECODE, FAIL, "can't pin sections")
    } /* end if */

    /* 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) {
        /* 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) {
            const H5FS_section_class_t *cls;    /* Class of section */

            /* Get section's class */
            cls = &fspace->sect_cls[(*node)->type];

            /* Update rest of free space manager data structures for node removal */
            if(H5FS_sect_unlink_rest(f, dxpl_id, fspace, cls, *node) < 0)
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "can't remove section from non-size tracking data structures")
#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:
#ifdef H5FS_DEBUG
    H5FS_assert(fspace);
#endif /* H5FS_DEBUG */
    FUNC_LEAVE_NOAPI(ret_value)
} /* H5FS_sect_find() */


/*-------------------------------------------------------------------------
 * Function:	H5FS_sect_serialize_size
 *
 * Purpose:	Determine serialized size of all sections in free space manager
 *              And adjust space on disk for storing serialized sections
 *
 * Return:	Success:	non-negative
 *		Failure:	negative
 *
 * Programmer:	Quincey Koziol
 *              Monday, May  8, 2006
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5FS_sect_serialize_size(H5F_t *f, hid_t dxpl_id, H5FS_t *fspace)
{
    herr_t ret_value = SUCCEED;         /* Return value */

    FUNC_ENTER_NOAPI_NOINIT(H5FS_sect_serialize_size)

    /* Check arguments. */
    HDassert(fspace);
#ifdef QAK
HDfprintf(stderr, "%s: Check 1.0 - 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->serial_size_count = %Zu\n", FUNC, 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", FUNC, fspace->sinfo->serial_size_count);
HDfprintf(stderr, "%s: fspace->serial_sect_count = %Hu\n", FUNC, fspace->serial_sect_count);
#endif /* QAK */
        sect_buf_size += fspace->sinfo->serial_size_count * MAX(1, ((H5V_log2_gen(fspace->serial_sect_count) + 7) / 8));

        /* 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;

        /* 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 = H5FS_SINFO_SIZE_DEFAULT;

#ifdef QAK
HDfprintf(stderr, "%s: Check 2.0 - fspace->sect_size = %Hu\n", FUNC, fspace->sect_size);
HDfprintf(stderr, "%s: fspace->alloc_sect_size = %Hu\n", FUNC, fspace->alloc_sect_size);
#endif /* QAK */
    if(fspace->sect_size > fspace->alloc_sect_size) {
        size_t new_size;        /* New size of space for serialized sections */
        haddr_t old_addr;       /* Old address of serialized sections */

/* Currently, the old block data is "thrown away" after the space is reallocated,
 * so 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 - 5/ 8/2006
 */
        /* Free previous serialized sections disk space */
        old_addr = fspace->sect_addr;
        if(H5MF_xfree(f, H5FD_MEM_FSPACE_SINFO, dxpl_id, old_addr, fspace->alloc_sect_size) < 0)
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to free free space sections")

        /* Compute new size */
        H5_ASSIGN_OVERFLOW(/* To: */ new_size, /* From: */ fspace->alloc_sect_size, /* From: */ hsize_t, /* To: */ size_t);
        while(new_size < fspace->sect_size)
            new_size *= (double)fspace->expand_percent / 100.0;
        fspace->alloc_sect_size = new_size;

        /* Allocate space for the new serialized sections on disk */
#ifdef QAK
HDfprintf(stderr, "%s: Allocating space for larger serialized sections, new_size = %Zu\n", FUNC, new_size);
HDfprintf(stderr, "%s: fspace->sect_size = %Hu\n", FUNC, fspace->sect_size);
#endif /* QAK */
        if(HADDR_UNDEF == (fspace->sect_addr = H5MF_alloc(f, H5FD_MEM_FSPACE_SINFO, dxpl_id, (hsize_t)fspace->alloc_sect_size)))
            HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL, "file allocation failed for free space sections")
#ifdef QAK
HDfprintf(stderr, "%s: old_addr = %a, fspace->sect_addr = %a\n", FUNC, old_addr, fspace->sect_addr);
#endif /* QAK */

        /* Move object in cache, if it actually was relocated */
        if(H5F_addr_ne(fspace->sect_addr, old_addr)) {
            if(H5AC_rename(f, H5AC_FSPACE_SINFO, old_addr, fspace->sect_addr) < 0)
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTRENAME, FAIL, "unable to move free space section info")
        } /* end if */
        else {
            /* Mark free space section as dirty */
            if(H5AC_mark_pinned_or_protected_entry_dirty(f, fspace->sinfo) < 0)
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space section info as dirty")
        } /* end else */

        /* Mark free space header as dirty */
        if(H5AC_mark_pinned_or_protected_entry_dirty(f, fspace) < 0)
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty")
    } /* end if */
    else {
        size_t decrease_threshold;      /* Size threshold for decreasing serialized section size */
        haddr_t old_addr;               /* Old address of serialized sections */

        /* Compute the threshold for decreasing the sections' serialized size */
        decrease_threshold = (size_t)(((size_t)fspace->alloc_sect_size * (double)fspace->shrink_percent) / 100.0);

        if(fspace->alloc_sect_size > H5FS_SINFO_SIZE_DEFAULT &&
                fspace->sect_size < decrease_threshold) {
            size_t new_size = 0;        /* New size of space for serialized sections */

/* Currently, the old block data is "thrown away" after the space is reallocated,
 * so 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 - 5/ 8/2006
 */
            /* Free previous serialized sections disk space */
            old_addr = fspace->sect_addr;
            if(H5MF_xfree(f, H5FD_MEM_FSPACE_SINFO, dxpl_id, old_addr, fspace->alloc_sect_size) < 0)
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to free free space sections")

            /* Compute new size */
            while(fspace->sect_size < decrease_threshold) {
                new_size = decrease_threshold;

                decrease_threshold *= (double)fspace->shrink_percent / 100.0;
            } /* end while */
            if(new_size < H5FS_SINFO_SIZE_DEFAULT)
                new_size = H5FS_SINFO_SIZE_DEFAULT;
            fspace->alloc_sect_size = new_size;

            /* Allocate space for the new serialized sections on disk */
#ifdef QAK
HDfprintf(stderr, "%s: Allocating space for smaller serialized sections, new_size = %Zu\n", FUNC, new_size);
#endif /* QAK */
            if(HADDR_UNDEF == (fspace->sect_addr = H5MF_alloc(f, H5FD_MEM_FSPACE_SINFO, dxpl_id, (hsize_t)fspace->alloc_sect_size)))
                HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL, "file allocation failed for free space sections")

            /* Move object in cache, if it actually was relocated */
            if(H5F_addr_ne(fspace->sect_addr, old_addr)) {
                if(H5AC_rename(f, H5AC_FSPACE_SINFO, old_addr, fspace->sect_addr) < 0)
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTRENAME, FAIL, "unable to move free space section info")
            } /* end if */
            else {
                /* Mark free space section as dirty */
                if(H5AC_mark_pinned_or_protected_entry_dirty(f, fspace->sinfo) < 0)
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space section info as dirty")
            } /* end else */

            /* Mark free space header as dirty */
            if(H5AC_mark_pinned_or_protected_entry_dirty(f, fspace) < 0)
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty")
        } /* end if */
    } /* end else */

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* H5FS_sect_serialize_size() */


/*-------------------------------------------------------------------------
 * Function:	H5FS_iterate_sect_cb
 *
 * Purpose:	Skip list iterator callback to iterate over free space sections
 *              of a particular size
 *
 * Return:	Success:	non-negative
 *
 *		Failure:	negative
 *
 * Programmer:	Quincey Koziol
 *              Saturday, May 13, 2006
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5FS_iterate_sect_cb(void *_item, void 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(H5FS_iterate_sect_cb)

    /* 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:	Success:	non-negative
 *
 *		Failure:	negative
 *
 * Programmer:	Quincey Koziol
 *              Saturday, May 13, 2006
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5FS_iterate_node_cb(void *_item, void 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(H5FS_iterate_node_cb)

    /* 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:	Success:	non-negative
 *
 *		Failure:	negative
 *
 * 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 */
    herr_t ret_value = SUCCEED;         /* Return value */

    FUNC_ENTER_NOAPI_NOINIT(H5FS_sect_iterate)

    /* Check arguments. */
    HDassert(fspace);
    HDassert(op);

    /* Check if we need to go get the sections */
    if(fspace->sinfo == NULL) {
        if(NULL == (fspace->sinfo = H5FS_sinfo_pin(f, dxpl_id, fspace)))
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTDECODE, FAIL, "can't pin sections")
    } /* end if */

#ifdef QAK
HDfprintf(stderr, "%s: fspace->hdr->sect_count = %Hu\n", FUNC, fspace->hdr->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 */

        /* 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:
    FUNC_LEAVE_NOAPI(ret_value)
} /* H5FS_sect_iterate() */


/*-------------------------------------------------------------------------
 * Function:	H5FS_get_sect_count
 *
 * Purpose:	Retrieve the number of sections managed
 *
 * Return:	Success:	non-negative
 *
 *		Failure:	negative
 *
 * Programmer:	Quincey Koziol
 *              Tuesday, May 30, 2006
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5FS_get_sect_count(const H5FS_t *fspace, hsize_t *nsects)
{
    FUNC_ENTER_NOAPI_NOFUNC(H5FS_get_sect_count)

    /* Check arguments. */
    HDassert(fspace);
    HDassert(nsects);

    /* Get the section count */
    *nsects = fspace->tot_sect_count;

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* H5FS_get_sect_count() */


/*-------------------------------------------------------------------------
 * Function:	H5FS_sect_change_class
 *
 * Purpose:	Make appropriate adjustments to internal data structures when
 *              a section changes class
 *
 * Return:	Success:	non-negative
 *
 *		Failure:	negative
 *
 * 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, unsigned 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 */
    herr_t ret_value = SUCCEED;                 /* Return value */

    FUNC_ENTER_NOAPI_NOINIT(H5FS_sect_change_class)

    /* Check arguments. */
    HDassert(fspace);
    HDassert(fspace->sinfo);
    HDassert(sect);
    HDassert(sect->type < fspace->nclasses);
    HDassert(new_class < fspace->nclasses);

    /* 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 = H5V_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 = 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, 0.5, (size_t)H5FS_DEFAULT_SKIPLIST_HEIGHT)))
                    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 = 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(f, dxpl_id, fspace) < 0)
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTCOMPUTE, FAIL, "can't adjust free space section size on disk")
    
    /* Mark free space sections as dirty */
    if(H5AC_mark_pinned_or_protected_entry_dirty(f, fspace->sinfo) < 0)
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space sections as dirty")

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* H5FS_sect_change_class() */

#ifdef H5FS_DEBUG

/*-------------------------------------------------------------------------
 * Function:	H5FS_sect_assert
 *
 * Purpose:	Verify that the sections managed are mostly sane
 *
 * Return:	Non-negative on success, negative on failure
 *
 * Programmer:	Quincey Koziol
 *		koziol@hdfgroup.org
 *		Jul 17 2006
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5FS_sect_assert(const H5FS_t *fspace)
{
    hsize_t separate_obj;       /* The number of separate objects managed */

    FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FS_sect_assert)
#ifdef QAK
HDfprintf(stderr, "%s: fspace->hdr->tot_sect_count = %Hu\n", "H5FS_sect_assert", fspace->hdr->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;