Coverage Report

Created: 2026-03-16 06:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Gdense.c
Line
Count
Source
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
 * Copyright by The HDF Group.                                               *
3
 * All rights reserved.                                                      *
4
 *                                                                           *
5
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
6
 * terms governing use, modification, and redistribution, is contained in    *
7
 * the LICENSE file, which can be found at the root of the source code       *
8
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
9
 * If you do not have access to either file, you may request a copy from     *
10
 * help@hdfgroup.org.                                                        *
11
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13
/*-------------------------------------------------------------------------
14
 *
15
 * Created:   H5Gdense.c
16
 *
17
 * Purpose:   Routines for operating on "dense" link storage for a
18
 *                      group in a file.
19
 *
20
 *-------------------------------------------------------------------------
21
 */
22
23
/****************/
24
/* Module Setup */
25
/****************/
26
27
#include "H5Gmodule.h" /* This source code file is part of the H5G module */
28
29
/***********/
30
/* Headers */
31
/***********/
32
#include "H5private.h"   /* Generic Functions     */
33
#include "H5Eprivate.h"  /* Error handling        */
34
#include "H5Gpkg.h"      /* Groups          */
35
#include "H5MMprivate.h" /* Memory management     */
36
#include "H5WBprivate.h" /* Wrapped Buffers                      */
37
38
/****************/
39
/* Local Macros */
40
/****************/
41
42
/* Fractal heap creation parameters for "dense" link storage */
43
0
#define H5G_FHEAP_MAN_WIDTH            4
44
0
#define H5G_FHEAP_MAN_START_BLOCK_SIZE 512
45
0
#define H5G_FHEAP_MAN_MAX_DIRECT_SIZE  (64 * 1024)
46
0
#define H5G_FHEAP_MAN_MAX_INDEX        32
47
0
#define H5G_FHEAP_MAN_START_ROOT_ROWS  1
48
0
#define H5G_FHEAP_CHECKSUM_DBLOCKS     true
49
0
#define H5G_FHEAP_MAX_MAN_SIZE         (4 * 1024)
50
51
/* v2 B-tree creation macros for 'name' field index */
52
0
#define H5G_NAME_BT2_NODE_SIZE  512
53
0
#define H5G_NAME_BT2_MERGE_PERC 40
54
0
#define H5G_NAME_BT2_SPLIT_PERC 100
55
56
/* v2 B-tree creation macros for 'corder' field index */
57
0
#define H5G_CORDER_BT2_NODE_SIZE  512
58
0
#define H5G_CORDER_BT2_MERGE_PERC 40
59
0
#define H5G_CORDER_BT2_SPLIT_PERC 100
60
61
/* Size of stack buffer for serialized link */
62
#define H5G_LINK_BUF_SIZE 128
63
64
/******************/
65
/* Local Typedefs */
66
/******************/
67
68
/* Data exchange structure to use when building table of links in group */
69
typedef struct {
70
    H5G_link_table_t *ltable;   /* Pointer to link table to build */
71
    size_t            curr_lnk; /* Current link to operate on */
72
} H5G_dense_bt_ud_t;
73
74
/*
75
 * Data exchange structure to pass through the v2 B-tree layer for the
76
 * H5B2_iterate function when iterating over densely stored links.
77
 */
78
typedef struct {
79
    /* downward (internal) */
80
    H5F_t  *f;     /* Pointer to file that fractal heap is in */
81
    H5HF_t *fheap; /* Fractal heap handle               */
82
    hsize_t count; /* # of links examined               */
83
84
    /* downward (from application) */
85
    hsize_t           skip;    /* Number of links to skip           */
86
    H5G_lib_iterate_t op;      /* Callback for each link            */
87
    void             *op_data; /* Callback data for each link       */
88
89
    /* upward */
90
    int op_ret; /* Return value from callback        */
91
} H5G_bt2_ud_it_t;
92
93
/*
94
 * Data exchange structure to pass through the fractal heap layer for the
95
 * H5HF_op function when iterating over densely stored links.
96
 */
97
typedef struct {
98
    /* downward (internal) */
99
    H5F_t *f; /* Pointer to file that fractal heap is in */
100
101
    /* upward */
102
    H5O_link_t *lnk; /* Copy of link                      */
103
} H5G_fh_ud_it_t;
104
105
/*
106
 * Data exchange structure for dense link storage.  This structure is
107
 * passed through the v2 B-tree layer when removing links.
108
 */
109
typedef struct {
110
    /* downward */
111
    H5G_bt2_ud_common_t common;          /* Common info for B-tree user data (must be first) */
112
    bool                rem_from_fheap;  /* Whether to remove the link from the fractal heap */
113
    haddr_t             corder_bt2_addr; /* Address of v2 B-tree indexing creation order */
114
    H5RS_str_t         *grp_full_path_r; /* Full path of group where link is removed */
115
    bool                replace_names;   /* Whether to replace the names of open objects */
116
} H5G_bt2_ud_rm_t;
117
118
/*
119
 * Data exchange structure to pass through the fractal heap layer for the
120
 * H5HF_op function when removing a link from densely stored links.
121
 */
122
typedef struct {
123
    /* downward */
124
    H5F_t      *f;               /* Pointer to file that fractal heap is in */
125
    haddr_t     corder_bt2_addr; /* Address of v2 B-tree indexing creation order */
126
    H5RS_str_t *grp_full_path_r; /* Full path of group where link is removed */
127
    bool        replace_names;   /* Whether to replace the names of open objects */
128
} H5G_fh_ud_rm_t;
129
130
/*
131
 * Data exchange structure for dense link storage.  This structure is
132
 * passed through the v2 B-tree layer when removing links by index.
133
 */
134
typedef struct {
135
    /* downward */
136
    H5F_t      *f;               /* Pointer to file that fractal heap is in */
137
    H5HF_t     *fheap;           /* Fractal heap handle               */
138
    H5_index_t  idx_type;        /* Primary index for removing link */
139
    haddr_t     other_bt2_addr;  /* Address of "other" v2 B-tree indexing link */
140
    H5RS_str_t *grp_full_path_r; /* Full path of group where link is removed */
141
} H5G_bt2_ud_rmbi_t;
142
143
/*
144
 * Data exchange structure to pass through the fractal heap layer for the
145
 * H5HF_op function when removing a link from densely stored links by index.
146
 */
147
typedef struct {
148
    /* downward */
149
    H5F_t *f; /* Pointer to file that fractal heap is in */
150
151
    /* upward */
152
    H5O_link_t *lnk; /* Pointer to link to remove */
153
} H5G_fh_ud_rmbi_t;
154
155
/*
156
 * Data exchange structure to pass through the v2 B-tree layer for the
157
 * H5B2_index function when retrieving the name of a link by index.
158
 */
159
typedef struct {
160
    /* downward (internal) */
161
    H5F_t  *f;     /* Pointer to file that fractal heap is in */
162
    H5HF_t *fheap; /* Fractal heap handle               */
163
164
    /* downward (from application) */
165
    char  *name;      /* Name buffer to fill               */
166
    size_t name_size; /* Size of name buffer to fill       */
167
168
    /* upward */
169
    size_t name_len; /* Full length of name               */
170
} H5G_bt2_ud_gnbi_t;
171
172
/*
173
 * Data exchange structure to pass through the fractal heap layer for the
174
 * H5HF_op function when retrieving the name of a link by index.
175
 */
176
typedef struct {
177
    /* downward (internal) */
178
    H5F_t *f; /* Pointer to file that fractal heap is in */
179
180
    /* downward (from application) */
181
    char  *name;      /* Name buffer to fill               */
182
    size_t name_size; /* Size of name buffer to fill       */
183
184
    /* upward */
185
    size_t name_len; /* Full length of name               */
186
} H5G_fh_ud_gnbi_t;
187
188
/*
189
 * Data exchange structure to pass through the v2 B-tree layer for the
190
 * H5B2_index function when retrieving a link by index.
191
 */
192
typedef struct {
193
    /* downward (internal) */
194
    H5F_t  *f;     /* Pointer to file that fractal heap is in */
195
    H5HF_t *fheap; /* Fractal heap handle               */
196
197
    /* upward */
198
    H5O_link_t *lnk; /* Pointer to link                   */
199
} H5G_bt2_ud_lbi_t;
200
201
/*
202
 * Data exchange structure to pass through the fractal heap layer for the
203
 * H5HF_op function when retrieving a link by index.
204
 */
205
typedef struct {
206
    /* downward (internal) */
207
    H5F_t *f; /* Pointer to file that fractal heap is in */
208
209
    /* upward */
210
    H5O_link_t *lnk; /* Pointer to link                   */
211
} H5G_fh_ud_lbi_t;
212
213
/********************/
214
/* Package Typedefs */
215
/********************/
216
217
/********************/
218
/* Local Prototypes */
219
/********************/
220
221
/*********************/
222
/* Package Variables */
223
/*********************/
224
225
/*****************************/
226
/* Library Private Variables */
227
/*****************************/
228
229
/*******************/
230
/* Local Variables */
231
/*******************/
232
233
/*-------------------------------------------------------------------------
234
 * Function:  H5G__dense_create
235
 *
236
 * Purpose: Creates dense link storage structures for a group
237
 *
238
 * Return:  Non-negative on success/Negative on failure
239
 *
240
 *-------------------------------------------------------------------------
241
 */
242
herr_t
243
H5G__dense_create(H5F_t *f, H5O_linfo_t *linfo, const H5O_pline_t *pline)
244
0
{
245
0
    H5HF_create_t fheap_cparam;        /* Fractal heap creation parameters */
246
0
    H5B2_create_t bt2_cparam;          /* v2 B-tree creation parameters */
247
0
    H5HF_t       *fheap      = NULL;   /* Fractal heap handle */
248
0
    H5B2_t       *bt2_name   = NULL;   /* v2 B-tree handle for names */
249
0
    H5B2_t       *bt2_corder = NULL;   /* v2 B-tree handle for creation order */
250
0
    size_t        fheap_id_len;        /* Fractal heap ID length */
251
0
    herr_t        ret_value = SUCCEED; /* Return value */
252
253
0
    FUNC_ENTER_PACKAGE
254
255
    /*
256
     * Check arguments.
257
     */
258
0
    assert(f);
259
0
    assert(linfo);
260
261
    /* Set fractal heap creation parameters */
262
    /* XXX: Give some control of these to applications? */
263
0
    memset(&fheap_cparam, 0, sizeof(fheap_cparam));
264
0
    fheap_cparam.managed.width            = H5G_FHEAP_MAN_WIDTH;
265
0
    fheap_cparam.managed.start_block_size = H5G_FHEAP_MAN_START_BLOCK_SIZE;
266
0
    fheap_cparam.managed.max_direct_size  = H5G_FHEAP_MAN_MAX_DIRECT_SIZE;
267
0
    fheap_cparam.managed.max_index        = H5G_FHEAP_MAN_MAX_INDEX;
268
0
    fheap_cparam.managed.start_root_rows  = H5G_FHEAP_MAN_START_ROOT_ROWS;
269
0
    fheap_cparam.checksum_dblocks         = H5G_FHEAP_CHECKSUM_DBLOCKS;
270
0
    fheap_cparam.max_man_size             = H5G_FHEAP_MAX_MAN_SIZE;
271
0
    if (pline)
272
0
        fheap_cparam.pline = *pline;
273
274
    /* Create fractal heap for storing links */
275
0
    if (NULL == (fheap = H5HF_create(f, &fheap_cparam)))
276
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create fractal heap");
277
278
    /* Retrieve the heap's address in the file */
279
0
    if (H5HF_get_heap_addr(fheap, &(linfo->fheap_addr)) < 0)
280
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get fractal heap address");
281
282
    /* Retrieve the heap's ID length in the file */
283
0
    if (H5HF_get_id_len(fheap, &fheap_id_len) < 0)
284
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTGETSIZE, FAIL, "can't get fractal heap ID length");
285
0
    assert(fheap_id_len == H5G_DENSE_FHEAP_ID_LEN);
286
287
    /* Create the name index v2 B-tree */
288
0
    memset(&bt2_cparam, 0, sizeof(bt2_cparam));
289
0
    bt2_cparam.cls       = H5G_BT2_NAME;
290
0
    bt2_cparam.node_size = (size_t)H5G_NAME_BT2_NODE_SIZE;
291
0
    H5_CHECK_OVERFLOW(fheap_id_len, /* From: */ hsize_t, /* To: */ uint32_t);
292
0
    bt2_cparam.rrec_size = 4 +                     /* Name's hash value */
293
0
                           (uint32_t)fheap_id_len; /* Fractal heap ID */
294
0
    bt2_cparam.split_percent = H5G_NAME_BT2_SPLIT_PERC;
295
0
    bt2_cparam.merge_percent = H5G_NAME_BT2_MERGE_PERC;
296
0
    if (NULL == (bt2_name = H5B2_create(f, &bt2_cparam, NULL)))
297
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create v2 B-tree for name index");
298
299
    /* Retrieve the v2 B-tree's address in the file */
300
0
    if (H5B2_get_addr(bt2_name, &(linfo->name_bt2_addr)) < 0)
301
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get v2 B-tree address for name index");
302
303
    /* Check if we should create a creation order index v2 B-tree */
304
0
    if (linfo->index_corder) {
305
        /* Create the creation order index v2 B-tree */
306
0
        memset(&bt2_cparam, 0, sizeof(bt2_cparam));
307
0
        bt2_cparam.cls       = H5G_BT2_CORDER;
308
0
        bt2_cparam.node_size = (size_t)H5G_CORDER_BT2_NODE_SIZE;
309
0
        H5_CHECK_OVERFLOW(fheap_id_len, /* From: */ hsize_t, /* To: */ uint32_t);
310
0
        bt2_cparam.rrec_size = 8 +                     /* Creation order value */
311
0
                               (uint32_t)fheap_id_len; /* Fractal heap ID */
312
0
        bt2_cparam.split_percent = H5G_CORDER_BT2_SPLIT_PERC;
313
0
        bt2_cparam.merge_percent = H5G_CORDER_BT2_MERGE_PERC;
314
0
        if (NULL == (bt2_corder = H5B2_create(f, &bt2_cparam, NULL)))
315
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create v2 B-tree for creation order index");
316
317
        /* Retrieve the v2 B-tree's address in the file */
318
0
        if (H5B2_get_addr(bt2_corder, &(linfo->corder_bt2_addr)) < 0)
319
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get v2 B-tree address for creation order index");
320
0
    } /* end if */
321
322
0
done:
323
    /* Close the open objects */
324
0
    if (fheap && H5HF_close(fheap) < 0)
325
0
        HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap");
326
0
    if (bt2_name && H5B2_close(bt2_name) < 0)
327
0
        HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index");
328
0
    if (bt2_corder && H5B2_close(bt2_corder) < 0)
329
0
        HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for creation order index");
330
331
0
    FUNC_LEAVE_NOAPI(ret_value)
332
0
} /* end H5G__dense_create() */
333
334
/*-------------------------------------------------------------------------
335
 * Function:  H5G__dense_insert
336
 *
337
 * Purpose: Insert a link into the  dense link storage structures for a group
338
 *
339
 * Return:  Non-negative on success/Negative on failure
340
 *
341
 *-------------------------------------------------------------------------
342
 */
343
herr_t
344
H5G__dense_insert(H5F_t *f, const H5O_linfo_t *linfo, const H5O_link_t *lnk)
345
0
{
346
0
    H5G_bt2_ud_ins_t udata;                       /* User data for v2 B-tree insertion */
347
0
    H5HF_t          *fheap      = NULL;           /* Fractal heap handle */
348
0
    H5B2_t          *bt2_name   = NULL;           /* v2 B-tree handle for name index */
349
0
    H5B2_t          *bt2_corder = NULL;           /* v2 B-tree handle for creation order index */
350
0
    size_t           link_size;                   /* Size of serialized link in the heap */
351
0
    H5WB_t          *wb = NULL;                   /* Wrapped buffer for link data */
352
0
    uint8_t          link_buf[H5G_LINK_BUF_SIZE]; /* Buffer for serializing link */
353
0
    void            *link_ptr  = NULL;            /* Pointer to serialized link */
354
0
    herr_t           ret_value = SUCCEED;         /* Return value */
355
356
0
    FUNC_ENTER_PACKAGE
357
358
    /*
359
     * Check arguments.
360
     */
361
0
    assert(f);
362
0
    assert(linfo);
363
0
    assert(lnk);
364
365
    /* Find out the size of buffer needed for serialized link */
366
0
    if ((link_size = H5O_msg_raw_size(f, H5O_LINK_ID, false, lnk)) == 0)
367
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTGETSIZE, FAIL, "can't get link size");
368
369
    /* Wrap the local buffer for serialized link */
370
0
    if (NULL == (wb = H5WB_wrap(link_buf, sizeof(link_buf))))
371
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't wrap buffer");
372
373
    /* Get a pointer to a buffer that's large enough for link */
374
0
    if (NULL == (link_ptr = H5WB_actual(wb, link_size)))
375
0
        HGOTO_ERROR(H5E_SYM, H5E_NOSPACE, FAIL, "can't get actual buffer");
376
377
    /* Create serialized form of link */
378
0
    if (H5O_msg_encode(f, H5O_LINK_ID, false, (unsigned char *)link_ptr, lnk) < 0)
379
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTENCODE, FAIL, "can't encode link");
380
381
    /* Open the fractal heap */
382
0
    if (NULL == (fheap = H5HF_open(f, linfo->fheap_addr)))
383
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap");
384
385
    /* Insert the serialized link into the fractal heap */
386
0
    if (H5HF_insert(fheap, link_size, link_ptr, udata.id) < 0)
387
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert link into fractal heap");
388
389
    /* Open the name index v2 B-tree */
390
0
    if (NULL == (bt2_name = H5B2_open(f, linfo->name_bt2_addr, NULL)))
391
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index");
392
393
    /* Create the callback information for v2 B-tree record insertion */
394
0
    udata.common.f             = f;
395
0
    udata.common.fheap         = fheap;
396
0
    udata.common.name          = lnk->name;
397
0
    udata.common.name_hash     = H5_checksum_lookup3(lnk->name, strlen(lnk->name), 0);
398
0
    udata.common.corder        = lnk->corder;
399
0
    udata.common.found_op      = NULL;
400
0
    udata.common.found_op_data = NULL;
401
    /* udata.id already set in H5HF_insert() call */
402
403
    /* Insert link into 'name' tracking v2 B-tree */
404
0
    if (H5B2_insert(bt2_name, &udata) < 0)
405
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert record into v2 B-tree");
406
407
    /* Check if we should create a creation order index v2 B-tree record */
408
0
    if (linfo->index_corder) {
409
        /* Open the creation order index v2 B-tree */
410
0
        assert(H5_addr_defined(linfo->corder_bt2_addr));
411
0
        if (NULL == (bt2_corder = H5B2_open(f, linfo->corder_bt2_addr, NULL)))
412
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for creation order index");
413
414
        /* Insert the record into the creation order index v2 B-tree */
415
0
        if (H5B2_insert(bt2_corder, &udata) < 0)
416
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert record into v2 B-tree");
417
0
    } /* end if */
418
419
0
done:
420
    /* Release resources */
421
0
    if (fheap && H5HF_close(fheap) < 0)
422
0
        HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap");
423
0
    if (bt2_name && H5B2_close(bt2_name) < 0)
424
0
        HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index");
425
0
    if (bt2_corder && H5B2_close(bt2_corder) < 0)
426
0
        HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for creation order index");
427
0
    if (wb && H5WB_unwrap(wb) < 0)
428
0
        HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close wrapped buffer");
429
430
0
    FUNC_LEAVE_NOAPI(ret_value)
431
0
} /* end H5G__dense_insert() */
432
433
/*-------------------------------------------------------------------------
434
 * Function:  H5G__dense_lookup_cb
435
 *
436
 * Purpose: Callback when a link is located in an index
437
 *
438
 * Return:  Non-negative on success/Negative on failure
439
 *
440
 *-------------------------------------------------------------------------
441
 */
442
static herr_t
443
H5G__dense_lookup_cb(const void *_lnk, void *_user_lnk)
444
0
{
445
0
    const H5O_link_t *lnk       = (const H5O_link_t *)_lnk; /* Record from B-tree */
446
0
    H5O_link_t       *user_lnk  = (H5O_link_t *)_user_lnk;  /* User data from v2 B-tree link lookup */
447
0
    herr_t            ret_value = SUCCEED;                  /* Return value */
448
449
0
    FUNC_ENTER_PACKAGE
450
451
    /*
452
     * Check arguments.
453
     */
454
0
    assert(lnk);
455
0
    assert(user_lnk);
456
457
    /* Copy link information */
458
0
    if (H5O_msg_copy(H5O_LINK_ID, lnk, user_lnk) == NULL)
459
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy link message");
460
461
0
done:
462
0
    FUNC_LEAVE_NOAPI(ret_value)
463
0
} /* end H5G__dense_lookup_cb() */
464
465
/*-------------------------------------------------------------------------
466
 * Function:  H5G__dense_lookup
467
 *
468
 * Purpose: Look up a link within a group that uses dense link storage
469
 *
470
 * Return:  SUCCEED/FAIL
471
 *
472
 *-------------------------------------------------------------------------
473
 */
474
herr_t
475
H5G__dense_lookup(H5F_t *f, const H5O_linfo_t *linfo, const char *name, bool *found, H5O_link_t *lnk)
476
0
{
477
0
    H5G_bt2_ud_common_t udata;               /* User data for v2 B-tree link lookup */
478
0
    H5HF_t             *fheap     = NULL;    /* Fractal heap handle */
479
0
    H5B2_t             *bt2_name  = NULL;    /* v2 B-tree handle for name index */
480
0
    herr_t              ret_value = SUCCEED; /* Return value */
481
482
0
    FUNC_ENTER_PACKAGE
483
484
    /*
485
     * Check arguments.
486
     */
487
0
    assert(f);
488
0
    assert(linfo);
489
0
    assert(name && *name);
490
0
    assert(found);
491
0
    assert(lnk);
492
493
    /* Open the fractal heap */
494
0
    if (NULL == (fheap = H5HF_open(f, linfo->fheap_addr)))
495
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap");
496
497
    /* Open the name index v2 B-tree */
498
0
    if (NULL == (bt2_name = H5B2_open(f, linfo->name_bt2_addr, NULL)))
499
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index");
500
501
    /* Construct the user data for v2 B-tree callback */
502
0
    udata.f             = f;
503
0
    udata.fheap         = fheap;
504
0
    udata.name          = name;
505
0
    udata.name_hash     = H5_checksum_lookup3(name, strlen(name), 0);
506
0
    udata.found_op      = H5G__dense_lookup_cb; /* v2 B-tree comparison callback */
507
0
    udata.found_op_data = lnk;
508
509
    /* Find & copy the named link in the 'name' index */
510
0
    if (H5B2_find(bt2_name, &udata, found, NULL, NULL) < 0)
511
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to locate link in name index");
512
513
0
done:
514
    /* Release resources */
515
0
    if (fheap && H5HF_close(fheap) < 0)
516
0
        HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap");
517
0
    if (bt2_name && H5B2_close(bt2_name) < 0)
518
0
        HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index");
519
520
0
    FUNC_LEAVE_NOAPI(ret_value)
521
0
} /* end H5G__dense_lookup() */
522
523
/*-------------------------------------------------------------------------
524
 * Function:  H5G__dense_lookup_by_idx_fh_cb
525
 *
526
 * Purpose: Callback for fractal heap operator, to make copy of link when
527
 *              when lookup up a link by index
528
 *
529
 * Return:  SUCCEED/FAIL
530
 *
531
 *-------------------------------------------------------------------------
532
 */
533
static herr_t
534
H5G__dense_lookup_by_idx_fh_cb(const void *obj, size_t obj_len, void *_udata)
535
0
{
536
0
    H5G_fh_ud_lbi_t *udata     = (H5G_fh_ud_lbi_t *)_udata; /* User data for fractal heap 'op' callback */
537
0
    H5O_link_t      *tmp_lnk   = NULL;                      /* Temporary pointer to link */
538
0
    herr_t           ret_value = SUCCEED;                   /* Return value */
539
540
0
    FUNC_ENTER_PACKAGE
541
542
    /* Decode link information & keep a copy */
543
0
    if (NULL == (tmp_lnk = (H5O_link_t *)H5O_msg_decode(udata->f, NULL, H5O_LINK_ID, obj_len,
544
0
                                                        (const unsigned char *)obj)))
545
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTDECODE, FAIL, "can't decode link");
546
547
    /* Copy link information */
548
0
    if (NULL == H5O_msg_copy(H5O_LINK_ID, tmp_lnk, udata->lnk))
549
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy link message");
550
551
0
done:
552
    /* Release the space allocated for the link */
553
0
    if (tmp_lnk)
554
0
        H5O_msg_free(H5O_LINK_ID, tmp_lnk);
555
556
0
    FUNC_LEAVE_NOAPI(ret_value)
557
0
} /* end H5G__dense_lookup_by_idx_fh_cb() */
558
559
/*-------------------------------------------------------------------------
560
 * Function:  H5G__dense_lookup_by_idx_bt2_cb
561
 *
562
 * Purpose: v2 B-tree callback for dense link storage lookup by index
563
 *
564
 * Return:  H5_ITER_ERROR/H5_ITER_CONT/H5_ITER_STOP
565
 *
566
 *-------------------------------------------------------------------------
567
 */
568
static herr_t
569
H5G__dense_lookup_by_idx_bt2_cb(const void *_record, void *_bt2_udata)
570
0
{
571
0
    const H5G_dense_bt2_name_rec_t *record    = (const H5G_dense_bt2_name_rec_t *)_record;
572
0
    H5G_bt2_ud_lbi_t               *bt2_udata = (H5G_bt2_ud_lbi_t *)_bt2_udata; /* User data for callback */
573
0
    H5G_fh_ud_lbi_t                 fh_udata;                 /* User data for fractal heap 'op' callback */
574
0
    int                             ret_value = H5_ITER_CONT; /* Return value */
575
576
0
    FUNC_ENTER_PACKAGE
577
578
    /* Prepare user data for callback */
579
    /* down */
580
0
    fh_udata.f   = bt2_udata->f;
581
0
    fh_udata.lnk = bt2_udata->lnk;
582
583
    /* Call fractal heap 'op' routine, to copy the link information */
584
0
    if (H5HF_op(bt2_udata->fheap, record->id, H5G__dense_lookup_by_idx_fh_cb, &fh_udata) < 0)
585
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTOPERATE, H5_ITER_ERROR, "link found callback failed");
586
587
0
done:
588
0
    FUNC_LEAVE_NOAPI(ret_value)
589
0
} /* end H5G__dense_lookup_by_idx_bt2_cb() */
590
591
/*-------------------------------------------------------------------------
592
 * Function:  H5G__dense_lookup_by_idx
593
 *
594
 * Purpose: Look up a link within a group that uses dense link storage,
595
 *              according to the order of an index
596
 *
597
 * Return:  Non-negative on success/Negative on failure
598
 *
599
 *-------------------------------------------------------------------------
600
 */
601
herr_t
602
H5G__dense_lookup_by_idx(H5F_t *f, const H5O_linfo_t *linfo, H5_index_t idx_type, H5_iter_order_t order,
603
                         hsize_t n, H5O_link_t *lnk)
604
0
{
605
0
    H5HF_t          *fheap  = NULL;       /* Fractal heap handle */
606
0
    H5G_link_table_t ltable = {0, NULL};  /* Table of links */
607
0
    H5B2_t          *bt2    = NULL;       /* v2 B-tree handle for index */
608
0
    haddr_t          bt2_addr;            /* Address of v2 B-tree to use for lookup */
609
0
    herr_t           ret_value = SUCCEED; /* Return value */
610
611
0
    FUNC_ENTER_PACKAGE
612
613
    /*
614
     * Check arguments.
615
     */
616
0
    assert(f);
617
0
    assert(linfo);
618
0
    assert(lnk);
619
620
    /* Determine the address of the index to use */
621
0
    if (idx_type == H5_INDEX_NAME) {
622
        /* Since names are hashed, getting them in strictly increasing or
623
         *      decreasing order requires building a table and sorting it.
624
         *      If the order is native, use the B-tree for names.
625
         */
626
0
        bt2_addr = HADDR_UNDEF;
627
0
    } /* end if */
628
0
    else {
629
0
        assert(idx_type == H5_INDEX_CRT_ORDER);
630
631
        /* This address may not be defined if creation order is tracked, but
632
         *      there's no index on it.  If there's no v2 B-tree that indexes
633
         *      the links and the order is native, use the B-tree for names.
634
         *      Otherwise, build a table.
635
         */
636
0
        bt2_addr = linfo->corder_bt2_addr;
637
0
    } /* end else */
638
639
    /* If the order is native and there's no B-tree for indexing the links,
640
     * use the B-tree for names instead of building a table to speed up the
641
     * process.
642
     */
643
0
    if (order == H5_ITER_NATIVE && !H5_addr_defined(bt2_addr)) {
644
0
        bt2_addr = linfo->name_bt2_addr;
645
0
        assert(H5_addr_defined(bt2_addr));
646
0
    } /* end if */
647
648
    /* If there is an index defined for the field, use it */
649
0
    if (H5_addr_defined(bt2_addr)) {
650
0
        H5G_bt2_ud_lbi_t udata; /* User data for v2 B-tree link lookup */
651
652
        /* Open the fractal heap */
653
0
        if (NULL == (fheap = H5HF_open(f, linfo->fheap_addr)))
654
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap");
655
656
        /* Open the index v2 B-tree */
657
0
        if (NULL == (bt2 = H5B2_open(f, bt2_addr, NULL)))
658
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for index");
659
660
        /* Construct the user data for v2 B-tree callback */
661
0
        udata.f     = f;
662
0
        udata.fheap = fheap;
663
0
        udata.lnk   = lnk;
664
665
        /* Find & copy the link in the appropriate index */
666
0
        if (H5B2_index(bt2, order, n, H5G__dense_lookup_by_idx_bt2_cb, &udata) < 0)
667
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to locate link in index");
668
0
    }      /* end if */
669
0
    else { /* Otherwise, we need to build a table of the links and sort it */
670
        /* Build the table of links for this group */
671
0
        if (H5G__dense_build_table(f, linfo, idx_type, order, &ltable) < 0)
672
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "error building table of links");
673
674
        /* Check for going out of bounds */
675
0
        if (n >= ltable.nlinks)
676
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "index out of bound");
677
678
        /* Copy link information */
679
0
        if (NULL == H5O_msg_copy(H5O_LINK_ID, &ltable.lnks[n], lnk))
680
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy link message");
681
0
    } /* end else */
682
683
0
done:
684
    /* Release resources */
685
0
    if (fheap && H5HF_close(fheap) < 0)
686
0
        HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap");
687
0
    if (bt2 && H5B2_close(bt2) < 0)
688
0
        HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for index");
689
0
    if (ltable.lnks && H5G__link_release_table(&ltable) < 0)
690
0
        HDONE_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link table");
691
692
0
    FUNC_LEAVE_NOAPI(ret_value)
693
0
} /* end H5G__dense_lookup_by_idx() */
694
695
/*-------------------------------------------------------------------------
696
 * Function:  H5G__dense_build_table_cb
697
 *
698
 * Purpose: Callback routine for building table of links from dense
699
 *              link storage.
700
 *
701
 * Return:  Success:        Non-negative
702
 *    Failure:  Negative
703
 *
704
 *-------------------------------------------------------------------------
705
 */
706
static herr_t
707
H5G__dense_build_table_cb(const H5O_link_t *lnk, void *_udata)
708
0
{
709
0
    H5G_dense_bt_ud_t *udata     = (H5G_dense_bt_ud_t *)_udata; /* 'User data' passed in */
710
0
    herr_t             ret_value = H5_ITER_CONT;                /* Return value */
711
712
0
    FUNC_ENTER_PACKAGE
713
714
    /* check arguments */
715
0
    assert(lnk);
716
0
    assert(udata);
717
0
    assert(udata->curr_lnk < udata->ltable->nlinks);
718
719
    /* Copy link information */
720
0
    if (H5O_msg_copy(H5O_LINK_ID, lnk, &(udata->ltable->lnks[udata->curr_lnk])) == NULL)
721
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, H5_ITER_ERROR, "can't copy link message");
722
723
    /* Increment number of links stored */
724
0
    udata->curr_lnk++;
725
726
0
done:
727
0
    FUNC_LEAVE_NOAPI(ret_value)
728
0
} /* end H5G__dense_build_table_cb() */
729
730
/*-------------------------------------------------------------------------
731
 * Function:  H5G__dense_build_table
732
 *
733
 * Purpose:     Builds a table containing a sorted list of links for a group
734
 *
735
 * Note:  Used for building table of links in non-native iteration order
736
 *    for an index
737
 *
738
 * Return:  Success:        Non-negative
739
 *    Failure:  Negative
740
 *
741
 *-------------------------------------------------------------------------
742
 */
743
herr_t
744
H5G__dense_build_table(H5F_t *f, const H5O_linfo_t *linfo, H5_index_t idx_type, H5_iter_order_t order,
745
                       H5G_link_table_t *ltable)
746
0
{
747
0
    herr_t ret_value = SUCCEED; /* Return value */
748
749
0
    FUNC_ENTER_PACKAGE
750
751
    /* Sanity check */
752
0
    assert(f);
753
0
    assert(linfo);
754
0
    assert(ltable);
755
756
    /* Set size of table */
757
0
    H5_CHECK_OVERFLOW(linfo->nlinks, /* From: */ hsize_t, /* To: */ size_t);
758
0
    ltable->nlinks = (size_t)linfo->nlinks;
759
760
    /* Allocate space for the table entries */
761
0
    if (ltable->nlinks > 0) {
762
0
        H5G_dense_bt_ud_t udata; /* User data for iteration callback */
763
764
        /* Allocate the table to store the links */
765
0
        if ((ltable->lnks = (H5O_link_t *)H5MM_calloc(sizeof(H5O_link_t) * ltable->nlinks)) == NULL)
766
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
767
768
        /* Initialize all links to invalid. NOTE: If H5O_link_t changes, update this loop. */
769
0
        for (size_t i = 0; i < ltable->nlinks; i++)
770
0
            ltable->lnks[i].type = H5L_TYPE_ERROR;
771
772
        /* Set up user data for iteration */
773
0
        udata.ltable   = ltable;
774
0
        udata.curr_lnk = 0;
775
776
        /* Iterate over the links in the group, building a table of the link messages */
777
0
        if (H5G__dense_iterate(f, linfo, H5_INDEX_NAME, H5_ITER_NATIVE, (hsize_t)0, NULL,
778
0
                               H5G__dense_build_table_cb, &udata) < 0)
779
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTNEXT, FAIL, "error iterating over links");
780
781
        /* Sort link table in correct iteration order */
782
0
        if (H5G__link_sort_table(ltable, idx_type, order) < 0)
783
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTSORT, FAIL, "error sorting link messages");
784
0
    } /* end if */
785
0
    else
786
0
        ltable->lnks = NULL;
787
788
0
done:
789
0
    FUNC_LEAVE_NOAPI(ret_value)
790
0
} /* end H5G__dense_build_table() */
791
792
/*-------------------------------------------------------------------------
793
 * Function:  H5G__dense_iterate_fh_cb
794
 *
795
 * Purpose: Callback for fractal heap operator, to make user's callback
796
 *              when iterating over links
797
 *
798
 * Return:  SUCCEED/FAIL
799
 *
800
 *-------------------------------------------------------------------------
801
 */
802
static herr_t
803
H5G__dense_iterate_fh_cb(const void *obj, size_t obj_len, void *_udata)
804
0
{
805
0
    H5G_fh_ud_it_t *udata     = (H5G_fh_ud_it_t *)_udata; /* User data for fractal heap 'op' callback */
806
0
    herr_t          ret_value = SUCCEED;                  /* Return value */
807
808
0
    FUNC_ENTER_PACKAGE
809
810
    /* Decode link information & keep a copy */
811
    /* (we make a copy instead of calling the user/library callback directly in
812
     *  this routine because this fractal heap 'op' callback routine is called
813
     *  with the direct block protected and if the callback routine invokes an
814
     *  HDF5 routine, it could attempt to re-protect that direct block for the
815
     *  heap, causing the HDF5 routine called to fail - QAK)
816
     */
817
0
    if (NULL == (udata->lnk = (H5O_link_t *)H5O_msg_decode(udata->f, NULL, H5O_LINK_ID, obj_len,
818
0
                                                           (const unsigned char *)obj)))
819
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTDECODE, FAIL, "can't decode link");
820
821
0
done:
822
0
    FUNC_LEAVE_NOAPI(ret_value)
823
0
} /* end H5G__dense_iterate_fh_cb() */
824
825
/*-------------------------------------------------------------------------
826
 * Function:  H5G__dense_iterate_bt2_cb
827
 *
828
 * Purpose: v2 B-tree callback for dense link storage iterator
829
 *
830
 * Return:  H5_ITER_ERROR/H5_ITER_CONT/H5_ITER_STOP
831
 *
832
 *-------------------------------------------------------------------------
833
 */
834
static herr_t
835
H5G__dense_iterate_bt2_cb(const void *_record, void *_bt2_udata)
836
0
{
837
0
    const H5G_dense_bt2_name_rec_t *record    = (const H5G_dense_bt2_name_rec_t *)_record;
838
0
    H5G_bt2_ud_it_t                *bt2_udata = (H5G_bt2_ud_it_t *)_bt2_udata; /* User data for callback */
839
0
    herr_t                          ret_value = H5_ITER_CONT;                  /* Return value */
840
841
0
    FUNC_ENTER_PACKAGE
842
843
    /* Check for skipping links */
844
0
    if (bt2_udata->skip > 0)
845
0
        --bt2_udata->skip;
846
0
    else {
847
0
        H5G_fh_ud_it_t fh_udata; /* User data for fractal heap 'op' callback */
848
849
        /* Prepare user data for callback */
850
        /* down */
851
0
        fh_udata.f = bt2_udata->f;
852
853
        /* Call fractal heap 'op' routine, to copy the link information */
854
0
        if (H5HF_op(bt2_udata->fheap, record->id, H5G__dense_iterate_fh_cb, &fh_udata) < 0)
855
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTOPERATE, H5_ITER_ERROR, "heap op callback failed");
856
857
        /* Make the callback */
858
0
        ret_value = (bt2_udata->op)(fh_udata.lnk, bt2_udata->op_data);
859
860
        /* Release the space allocated for the link */
861
0
        H5O_msg_free(H5O_LINK_ID, fh_udata.lnk);
862
0
    } /* end else */
863
864
    /* Increment the number of entries passed through */
865
    /* (whether we skipped them or not) */
866
0
    bt2_udata->count++;
867
868
    /* Check for callback failure and pass along return value */
869
0
    if (ret_value < 0)
870
0
        HERROR(H5E_SYM, H5E_CANTNEXT, "iteration operator failed");
871
872
0
done:
873
0
    FUNC_LEAVE_NOAPI(ret_value)
874
0
} /* end H5G__dense_iterate_bt2_cb() */
875
876
/*-------------------------------------------------------------------------
877
 * Function:  H5G__dense_iterate
878
 *
879
 * Purpose: Iterate over the objects in a group using dense link storage
880
 *
881
 * Return:  Non-negative on success/Negative on failure
882
 *
883
 *-------------------------------------------------------------------------
884
 */
885
herr_t
886
H5G__dense_iterate(H5F_t *f, const H5O_linfo_t *linfo, H5_index_t idx_type, H5_iter_order_t order,
887
                   hsize_t skip, hsize_t *last_lnk, H5G_lib_iterate_t op, void *op_data)
888
0
{
889
0
    H5HF_t          *fheap  = NULL;      /* Fractal heap handle */
890
0
    H5G_link_table_t ltable = {0, NULL}; /* Table of links */
891
0
    H5B2_t          *bt2    = NULL;      /* v2 B-tree handle for index */
892
0
    haddr_t          bt2_addr;           /* Address of v2 B-tree to use for lookup */
893
0
    herr_t           ret_value = FAIL;   /* Return value */
894
895
0
    FUNC_ENTER_PACKAGE
896
897
    /*
898
     * Check arguments.
899
     */
900
0
    assert(f);
901
0
    assert(linfo);
902
0
    assert(op);
903
904
    /* Determine the address of the index to use */
905
0
    if (idx_type == H5_INDEX_NAME) {
906
        /* Since names are hashed, getting them in strictly increasing or
907
         * decreasing order requires building a table and sorting it. If
908
         * the order is native, use the B-tree for names.
909
         */
910
0
        bt2_addr = HADDR_UNDEF;
911
0
    } /* end if */
912
0
    else {
913
0
        assert(idx_type == H5_INDEX_CRT_ORDER);
914
915
        /* This address may not be defined if creation order is tracked, but
916
         *      there's no index on it.  If there's no v2 B-tree that indexes
917
         *      the links and the order is native, use the B-tree for names.
918
         *      Otherwise, build a table.
919
         */
920
0
        bt2_addr = linfo->corder_bt2_addr;
921
0
    } /* end else */
922
923
    /* If the order is native and there's no B-tree for indexing the links,
924
     * use the B-tree for names instead of building a table to speed up the
925
     * process.
926
     */
927
0
    if (order == H5_ITER_NATIVE && !H5_addr_defined(bt2_addr)) {
928
0
        assert(H5_addr_defined(linfo->name_bt2_addr));
929
0
        bt2_addr = linfo->name_bt2_addr;
930
0
    } /* end if */
931
932
    /* Check on iteration order */
933
0
    if (order == H5_ITER_NATIVE) {
934
0
        H5G_bt2_ud_it_t udata; /* User data for iterator callback */
935
936
        /* Sanity check */
937
0
        assert(H5_addr_defined(bt2_addr));
938
939
        /* Open the fractal heap */
940
0
        if (NULL == (fheap = H5HF_open(f, linfo->fheap_addr)))
941
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap");
942
943
        /* Open the index v2 B-tree */
944
0
        if (NULL == (bt2 = H5B2_open(f, bt2_addr, NULL)))
945
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for index");
946
947
        /* Construct the user data for v2 B-tree iterator callback */
948
0
        udata.f       = f;
949
0
        udata.fheap   = fheap;
950
0
        udata.skip    = skip;
951
0
        udata.count   = 0;
952
0
        udata.op      = op;
953
0
        udata.op_data = op_data;
954
955
        /* Iterate over the records in the v2 B-tree's "native" order */
956
        /* (by hash of name) */
957
0
        if ((ret_value = H5B2_iterate(bt2, H5G__dense_iterate_bt2_cb, &udata)) < 0)
958
0
            HERROR(H5E_SYM, H5E_BADITER, "link iteration failed");
959
960
        /* Update the last link examined, if requested */
961
0
        if (last_lnk)
962
0
            *last_lnk = udata.count;
963
0
    } /* end if */
964
0
    else {
965
        /* Build the table of links for this group */
966
0
        if (H5G__dense_build_table(f, linfo, idx_type, order, &ltable) < 0)
967
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "error building table of links");
968
969
        /* Iterate over links in table */
970
0
        if ((ret_value = H5G__link_iterate_table(&ltable, skip, last_lnk, op, op_data)) < 0)
971
0
            HERROR(H5E_SYM, H5E_CANTNEXT, "iteration operator failed");
972
0
    } /* end else */
973
974
0
done:
975
    /* Release resources */
976
0
    if (fheap && H5HF_close(fheap) < 0)
977
0
        HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap");
978
0
    if (bt2 && H5B2_close(bt2) < 0)
979
0
        HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for index");
980
0
    if (ltable.lnks && H5G__link_release_table(&ltable) < 0)
981
0
        HDONE_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link table");
982
983
0
    FUNC_LEAVE_NOAPI(ret_value)
984
0
} /* end H5G__dense_iterate() */
985
986
/*-------------------------------------------------------------------------
987
 * Function:  H5G__dense_get_name_by_idx_fh_cb
988
 *
989
 * Purpose: Callback for fractal heap operator, to retrieve name according
990
 *              to an index
991
 *
992
 * Return:  SUCCEED/FAIL
993
 *
994
 *-------------------------------------------------------------------------
995
 */
996
static herr_t
997
H5G__dense_get_name_by_idx_fh_cb(const void *obj, size_t obj_len, void *_udata)
998
0
{
999
0
    H5G_fh_ud_gnbi_t *udata = (H5G_fh_ud_gnbi_t *)_udata; /* User data for fractal heap 'op' callback */
1000
0
    H5O_link_t       *lnk;                                /* Pointer to link created from heap object */
1001
0
    herr_t            ret_value = SUCCEED;                /* Return value */
1002
1003
0
    FUNC_ENTER_PACKAGE
1004
1005
    /* Decode link information */
1006
0
    if (NULL == (lnk = (H5O_link_t *)H5O_msg_decode(udata->f, NULL, H5O_LINK_ID, obj_len,
1007
0
                                                    (const unsigned char *)obj)))
1008
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTDECODE, FAIL, "can't decode link");
1009
1010
    /* Get the length of the name */
1011
0
    udata->name_len = strlen(lnk->name);
1012
1013
    /* Copy the name into the user's buffer, if given */
1014
0
    if (udata->name) {
1015
0
        strncpy(udata->name, lnk->name, MIN((udata->name_len + 1), udata->name_size));
1016
0
        if (udata->name_len >= udata->name_size)
1017
0
            udata->name[udata->name_size - 1] = '\0';
1018
0
    } /* end if */
1019
1020
    /* Release the space allocated for the link */
1021
0
    H5O_msg_free(H5O_LINK_ID, lnk);
1022
1023
0
done:
1024
0
    FUNC_LEAVE_NOAPI(ret_value)
1025
0
} /* end H5G__dense_get_name_by_idx_fh_cb() */
1026
1027
/*-------------------------------------------------------------------------
1028
 * Function:  H5G__dense_get_name_by_idx_bt2_cb
1029
 *
1030
 * Purpose: v2 B-tree callback for dense link storage 'get name by idx' call
1031
 *
1032
 * Return:  Non-negative on success/Negative on failure
1033
 *
1034
 *-------------------------------------------------------------------------
1035
 */
1036
static herr_t
1037
H5G__dense_get_name_by_idx_bt2_cb(const void *_record, void *_bt2_udata)
1038
0
{
1039
0
    const H5G_dense_bt2_name_rec_t *record    = (const H5G_dense_bt2_name_rec_t *)_record;
1040
0
    H5G_bt2_ud_gnbi_t              *bt2_udata = (H5G_bt2_ud_gnbi_t *)_bt2_udata; /* User data for callback */
1041
0
    H5G_fh_ud_gnbi_t                fh_udata;            /* User data for fractal heap 'op' callback */
1042
0
    herr_t                          ret_value = SUCCEED; /* Return value */
1043
1044
0
    FUNC_ENTER_PACKAGE
1045
1046
    /* Prepare user data for callback */
1047
    /* down */
1048
0
    fh_udata.f         = bt2_udata->f;
1049
0
    fh_udata.name      = bt2_udata->name;
1050
0
    fh_udata.name_size = bt2_udata->name_size;
1051
1052
    /* Call fractal heap 'op' routine, to perform user callback */
1053
0
    if (H5HF_op(bt2_udata->fheap, record->id, H5G__dense_get_name_by_idx_fh_cb, &fh_udata) < 0)
1054
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTOPERATE, FAIL, "link found callback failed");
1055
1056
    /* Set the name's full length to return */
1057
0
    bt2_udata->name_len = fh_udata.name_len;
1058
1059
0
done:
1060
0
    FUNC_LEAVE_NOAPI(ret_value)
1061
0
} /* end H5G__dense_get_name_by_idx_bt2_cb() */
1062
1063
/*-------------------------------------------------------------------------
1064
 * Function:  H5G__dense_get_name_by_idx
1065
 *
1066
 * Purpose:     Returns the name of objects in the group by giving index.
1067
 *
1068
 * Return:  Non-negative on success/Negative on failure
1069
 *
1070
 *-------------------------------------------------------------------------
1071
 */
1072
herr_t
1073
H5G__dense_get_name_by_idx(H5F_t *f, H5O_linfo_t *linfo, H5_index_t idx_type, H5_iter_order_t order,
1074
                           hsize_t n, char *name, size_t name_size, size_t *name_len)
1075
0
{
1076
0
    H5HF_t          *fheap  = NULL;       /* Fractal heap handle */
1077
0
    H5G_link_table_t ltable = {0, NULL};  /* Table of links */
1078
0
    H5B2_t          *bt2    = NULL;       /* v2 B-tree handle for index */
1079
0
    haddr_t          bt2_addr;            /* Address of v2 B-tree to use for lookup */
1080
0
    herr_t           ret_value = SUCCEED; /* Return value */
1081
1082
0
    FUNC_ENTER_PACKAGE
1083
1084
    /*
1085
     * Check arguments.
1086
     */
1087
0
    assert(f);
1088
0
    assert(linfo);
1089
1090
    /* Determine the address of the index to use */
1091
0
    if (idx_type == H5_INDEX_NAME) {
1092
        /* Since names are hashed, getting them in strictly increasing or
1093
         * decreasing order requires building a table and sorting it.  If
1094
         * the order is native, use the B-tree for names.
1095
         */
1096
0
        bt2_addr = HADDR_UNDEF;
1097
0
    } /* end if */
1098
0
    else {
1099
0
        assert(idx_type == H5_INDEX_CRT_ORDER);
1100
1101
        /* This address may not be defined if creation order is tracked, but
1102
         *      there's no index on it.  If there's no v2 B-tree that indexes
1103
         *      the links and the order is native, use the B-tree for names.
1104
         *      Otherwise, build a table.
1105
         */
1106
0
        bt2_addr = linfo->corder_bt2_addr;
1107
0
    } /* end else */
1108
1109
    /* If the order is native and there's no B-tree for indexing the links,
1110
     * use the B-tree for names instead of building a table to speed up the
1111
     * process.
1112
     */
1113
0
    if (order == H5_ITER_NATIVE && !H5_addr_defined(bt2_addr)) {
1114
0
        bt2_addr = linfo->name_bt2_addr;
1115
0
        assert(H5_addr_defined(bt2_addr));
1116
0
    } /* end if */
1117
1118
    /* If there is an index defined for the field, use it */
1119
0
    if (H5_addr_defined(bt2_addr)) {
1120
0
        H5G_bt2_ud_gnbi_t udata; /* User data for v2 B-tree callback */
1121
1122
        /* Open the fractal heap */
1123
0
        if (NULL == (fheap = H5HF_open(f, linfo->fheap_addr)))
1124
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap");
1125
1126
        /* Open the index v2 B-tree */
1127
0
        if (NULL == (bt2 = H5B2_open(f, bt2_addr, NULL)))
1128
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for index");
1129
1130
        /* Set up the user data for the v2 B-tree 'record remove' callback */
1131
0
        udata.f         = f;
1132
0
        udata.fheap     = fheap;
1133
0
        udata.name      = name;
1134
0
        udata.name_size = name_size;
1135
1136
        /* Retrieve the name according to the v2 B-tree's index order */
1137
0
        if (H5B2_index(bt2, order, n, H5G__dense_get_name_by_idx_bt2_cb, &udata) < 0)
1138
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTLIST, FAIL, "can't locate object in v2 B-tree");
1139
1140
        /* Set return value */
1141
0
        *name_len = udata.name_len;
1142
0
    }      /* end if */
1143
0
    else { /* Otherwise, we need to build a table of the links and sort it */
1144
        /* Build the table of links for this group */
1145
0
        if (H5G__dense_build_table(f, linfo, idx_type, order, &ltable) < 0)
1146
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "error building table of links");
1147
1148
        /* Check for going out of bounds */
1149
0
        if (n >= ltable.nlinks)
1150
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "index out of bound");
1151
1152
        /* Get the length of the name */
1153
0
        *name_len = strlen(ltable.lnks[n].name);
1154
1155
        /* Copy the name into the user's buffer, if given */
1156
0
        if (name) {
1157
0
            strncpy(name, ltable.lnks[n].name, MIN((*name_len + 1), name_size));
1158
0
            if (*name_len >= name_size)
1159
0
                name[name_size - 1] = '\0';
1160
0
        } /* end if */
1161
0
    }     /* end else */
1162
1163
0
done:
1164
    /* Release resources */
1165
0
    if (fheap && H5HF_close(fheap) < 0)
1166
0
        HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap");
1167
0
    if (bt2 && H5B2_close(bt2) < 0)
1168
0
        HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for index");
1169
0
    if (ltable.lnks && H5G__link_release_table(&ltable) < 0)
1170
0
        HDONE_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link table");
1171
1172
0
    FUNC_LEAVE_NOAPI(ret_value)
1173
0
} /* end H5G__dense_get_name_by_idx() */
1174
1175
/*-------------------------------------------------------------------------
1176
 * Function:  H5G__dense_remove_fh_cb
1177
 *
1178
 * Purpose: Callback for fractal heap operator when removing links
1179
 *
1180
 * Return:  SUCCEED/FAIL
1181
 *
1182
 *-------------------------------------------------------------------------
1183
 */
1184
static herr_t
1185
H5G__dense_remove_fh_cb(const void *obj, size_t obj_len, void *_udata)
1186
0
{
1187
0
    H5G_fh_ud_rm_t *udata     = (H5G_fh_ud_rm_t *)_udata; /* User data for fractal heap 'op' callback */
1188
0
    H5O_link_t     *lnk       = NULL;                     /* Pointer to link created from heap object */
1189
0
    H5B2_t         *bt2       = NULL;                     /* v2 B-tree handle for index */
1190
0
    herr_t          ret_value = SUCCEED;                  /* Return value */
1191
1192
0
    FUNC_ENTER_PACKAGE
1193
1194
    /* Decode link information */
1195
0
    if (NULL == (lnk = (H5O_link_t *)H5O_msg_decode(udata->f, NULL, H5O_LINK_ID, obj_len,
1196
0
                                                    (const unsigned char *)obj)))
1197
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTDECODE, FAIL, "can't decode link");
1198
1199
    /* Check for removing the link from the creation order index */
1200
0
    if (H5_addr_defined(udata->corder_bt2_addr)) {
1201
0
        H5G_bt2_ud_common_t bt2_udata; /* Info for B-tree callbacks */
1202
1203
        /* Open the creation order index v2 B-tree */
1204
0
        if (NULL == (bt2 = H5B2_open(udata->f, udata->corder_bt2_addr, NULL)))
1205
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for creation order index");
1206
1207
        /* Set up the user data for the v2 B-tree 'record remove' callback */
1208
0
        assert(lnk->corder_valid);
1209
0
        bt2_udata.corder = lnk->corder;
1210
1211
        /* Remove the record from the name index v2 B-tree */
1212
0
        if (H5B2_remove(bt2, &bt2_udata, NULL, NULL) < 0)
1213
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTREMOVE, FAIL,
1214
0
                        "unable to remove link from creation order index v2 B-tree");
1215
0
    } /* end if */
1216
1217
    /* Replace open objects' names, if requested */
1218
0
    if (udata->replace_names)
1219
0
        if (H5G__link_name_replace(udata->f, udata->grp_full_path_r, lnk) < 0)
1220
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTRENAME, FAIL, "unable to rename open objects");
1221
1222
    /* Perform the deletion action on the link, if requested */
1223
    /* (call message "delete" callback directly: *ick* - QAK) */
1224
0
    if (H5O_link_delete(udata->f, NULL, lnk) < 0)
1225
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete link");
1226
1227
0
done:
1228
    /* Release resources */
1229
0
    if (bt2 && H5B2_close(bt2) < 0)
1230
0
        HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for creation order index");
1231
0
    if (lnk)
1232
0
        H5O_msg_free(H5O_LINK_ID, lnk);
1233
1234
0
    FUNC_LEAVE_NOAPI(ret_value)
1235
0
} /* end H5G__dense_remove_fh_cb() */
1236
1237
/*-------------------------------------------------------------------------
1238
 * Function:  H5G__dense_remove_bt2_cb
1239
 *
1240
 * Purpose: v2 B-tree callback for dense link storage record removal
1241
 *
1242
 * Return:  Non-negative on success/Negative on failure
1243
 *
1244
 *-------------------------------------------------------------------------
1245
 */
1246
static herr_t
1247
H5G__dense_remove_bt2_cb(const void *_record, void *_bt2_udata)
1248
0
{
1249
0
    const H5G_dense_bt2_name_rec_t *record    = (const H5G_dense_bt2_name_rec_t *)_record;
1250
0
    H5G_bt2_ud_rm_t                *bt2_udata = (H5G_bt2_ud_rm_t *)_bt2_udata; /* User data for callback */
1251
0
    H5G_fh_ud_rm_t                  fh_udata;            /* User data for fractal heap 'op' callback */
1252
0
    herr_t                          ret_value = SUCCEED; /* Return value */
1253
1254
0
    FUNC_ENTER_PACKAGE
1255
1256
    /* Set up the user data for fractal heap 'op' callback */
1257
0
    fh_udata.f               = bt2_udata->common.f;
1258
0
    fh_udata.corder_bt2_addr = bt2_udata->corder_bt2_addr;
1259
0
    fh_udata.grp_full_path_r = bt2_udata->grp_full_path_r;
1260
0
    fh_udata.replace_names   = bt2_udata->replace_names;
1261
1262
    /* Call fractal heap 'op' routine, to perform user callback */
1263
0
    if (H5HF_op(bt2_udata->common.fheap, record->id, H5G__dense_remove_fh_cb, &fh_udata) < 0)
1264
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTOPERATE, FAIL, "link removal callback failed");
1265
1266
    /* Remove record from fractal heap, if requested */
1267
0
    if (bt2_udata->rem_from_fheap)
1268
0
        if (H5HF_remove(bt2_udata->common.fheap, record->id) < 0)
1269
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTREMOVE, FAIL, "unable to remove link from fractal heap");
1270
1271
0
done:
1272
0
    FUNC_LEAVE_NOAPI(ret_value)
1273
0
} /* end H5G__dense_remove_bt2_cb() */
1274
1275
/*-------------------------------------------------------------------------
1276
 * Function:  H5G__dense_remove
1277
 *
1278
 * Purpose: Remove a link from the dense storage of a group
1279
 *
1280
 * Return:  Non-negative on success/Negative on failure
1281
 *
1282
 *-------------------------------------------------------------------------
1283
 */
1284
herr_t
1285
H5G__dense_remove(H5F_t *f, const H5O_linfo_t *linfo, H5RS_str_t *grp_full_path_r, const char *name)
1286
0
{
1287
0
    H5HF_t         *fheap = NULL;        /* Fractal heap handle */
1288
0
    H5G_bt2_ud_rm_t udata;               /* User data for v2 B-tree record removal */
1289
0
    H5B2_t         *bt2       = NULL;    /* v2 B-tree handle for index */
1290
0
    herr_t          ret_value = SUCCEED; /* Return value */
1291
1292
0
    FUNC_ENTER_PACKAGE
1293
1294
    /*
1295
     * Check arguments.
1296
     */
1297
0
    assert(f);
1298
0
    assert(linfo);
1299
0
    assert(name && *name);
1300
1301
    /* Open the fractal heap */
1302
0
    if (NULL == (fheap = H5HF_open(f, linfo->fheap_addr)))
1303
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap");
1304
1305
    /* Open the name index v2 B-tree */
1306
0
    if (NULL == (bt2 = H5B2_open(f, linfo->name_bt2_addr, NULL)))
1307
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index");
1308
1309
    /* Set up the user data for the v2 B-tree 'record remove' callback */
1310
0
    udata.common.f             = f;
1311
0
    udata.common.fheap         = fheap;
1312
0
    udata.common.name          = name;
1313
0
    udata.common.name_hash     = H5_checksum_lookup3(name, strlen(name), 0);
1314
0
    udata.common.found_op      = NULL;
1315
0
    udata.common.found_op_data = NULL;
1316
0
    udata.rem_from_fheap       = true;
1317
0
    udata.corder_bt2_addr      = linfo->corder_bt2_addr;
1318
0
    udata.grp_full_path_r      = grp_full_path_r;
1319
0
    udata.replace_names        = true;
1320
1321
    /* Remove the record from the name index v2 B-tree */
1322
0
    if (H5B2_remove(bt2, &udata, H5G__dense_remove_bt2_cb, &udata) < 0)
1323
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTREMOVE, FAIL, "unable to remove link from name index v2 B-tree");
1324
1325
0
done:
1326
    /* Release resources */
1327
0
    if (fheap && H5HF_close(fheap) < 0)
1328
0
        HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap");
1329
0
    if (bt2 && H5B2_close(bt2) < 0)
1330
0
        HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index");
1331
1332
0
    FUNC_LEAVE_NOAPI(ret_value)
1333
0
} /* end H5G__dense_remove() */
1334
1335
/*-------------------------------------------------------------------------
1336
 * Function:  H5G__dense_remove_by_idx_fh_cb
1337
 *
1338
 * Purpose: Callback for fractal heap operator when removing links by index
1339
 *
1340
 * Return:  SUCCEED/FAIL
1341
 *
1342
 *-------------------------------------------------------------------------
1343
 */
1344
static herr_t
1345
H5G__dense_remove_by_idx_fh_cb(const void *obj, size_t obj_len, void *_udata)
1346
0
{
1347
0
    H5G_fh_ud_rmbi_t *udata     = (H5G_fh_ud_rmbi_t *)_udata; /* User data for fractal heap 'op' callback */
1348
0
    herr_t            ret_value = SUCCEED;                    /* Return value */
1349
1350
0
    FUNC_ENTER_PACKAGE
1351
1352
    /* Decode link information */
1353
0
    if (NULL == (udata->lnk = (H5O_link_t *)H5O_msg_decode(udata->f, NULL, H5O_LINK_ID, obj_len,
1354
0
                                                           (const unsigned char *)obj)))
1355
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTDECODE, H5_ITER_ERROR, "can't decode link");
1356
1357
    /* Can't operate on link here because the fractal heap block is locked */
1358
1359
0
done:
1360
0
    FUNC_LEAVE_NOAPI(ret_value)
1361
0
} /* end H5G__dense_remove_by_idx_fh_cb() */
1362
1363
/*-------------------------------------------------------------------------
1364
 * Function:  H5G__dense_remove_by_idx_bt2_cb
1365
 *
1366
 * Purpose: v2 B-tree callback for dense link storage record removal by index
1367
 *
1368
 * Return:  Non-negative on success/Negative on failure
1369
 *
1370
 *-------------------------------------------------------------------------
1371
 */
1372
static herr_t
1373
H5G__dense_remove_by_idx_bt2_cb(const void *_record, void *_bt2_udata)
1374
0
{
1375
0
    H5G_bt2_ud_rmbi_t *bt2_udata = (H5G_bt2_ud_rmbi_t *)_bt2_udata; /* User data for callback */
1376
0
    H5G_fh_ud_rmbi_t   fh_udata;            /* User data for fractal heap 'op' callback */
1377
0
    H5B2_t            *bt2 = NULL;          /* v2 B-tree handle for index */
1378
0
    const uint8_t     *heap_id;             /* Heap ID for link */
1379
0
    herr_t             ret_value = SUCCEED; /* Return value */
1380
1381
0
    FUNC_ENTER_PACKAGE
1382
1383
    /* Determine the index being used */
1384
0
    if (bt2_udata->idx_type == H5_INDEX_NAME) {
1385
0
        const H5G_dense_bt2_name_rec_t *record = (const H5G_dense_bt2_name_rec_t *)_record;
1386
1387
        /* Set the heap ID to operate on */
1388
0
        heap_id = record->id;
1389
0
    } /* end if */
1390
0
    else {
1391
0
        const H5G_dense_bt2_corder_rec_t *record = (const H5G_dense_bt2_corder_rec_t *)_record;
1392
1393
0
        assert(bt2_udata->idx_type == H5_INDEX_CRT_ORDER);
1394
1395
        /* Set the heap ID to operate on */
1396
0
        heap_id = record->id;
1397
0
    } /* end else */
1398
1399
    /* Set up the user data for fractal heap 'op' callback */
1400
0
    fh_udata.f   = bt2_udata->f;
1401
0
    fh_udata.lnk = NULL;
1402
1403
    /* Call fractal heap 'op' routine, to perform user callback */
1404
0
    if (H5HF_op(bt2_udata->fheap, heap_id, H5G__dense_remove_by_idx_fh_cb, &fh_udata) < 0)
1405
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTOPERATE, FAIL, "link removal callback failed");
1406
0
    assert(fh_udata.lnk);
1407
1408
    /* Check for removing the link from the "other" index (creation order, when name used and vice versa) */
1409
0
    if (H5_addr_defined(bt2_udata->other_bt2_addr)) {
1410
0
        H5G_bt2_ud_common_t other_bt2_udata; /* Info for B-tree callbacks */
1411
1412
        /* Determine the index being used */
1413
0
        if (bt2_udata->idx_type == H5_INDEX_NAME) {
1414
            /* Set up the user data for the v2 B-tree 'record remove' callback */
1415
0
            other_bt2_udata.corder = fh_udata.lnk->corder;
1416
0
        } /* end if */
1417
0
        else {
1418
0
            assert(bt2_udata->idx_type == H5_INDEX_CRT_ORDER);
1419
1420
            /* Set up the user data for the v2 B-tree 'record remove' callback */
1421
0
            other_bt2_udata.f     = bt2_udata->f;
1422
0
            other_bt2_udata.fheap = bt2_udata->fheap;
1423
0
            other_bt2_udata.name  = fh_udata.lnk->name;
1424
0
            other_bt2_udata.name_hash =
1425
0
                H5_checksum_lookup3(fh_udata.lnk->name, strlen(fh_udata.lnk->name), 0);
1426
0
            other_bt2_udata.found_op      = NULL;
1427
0
            other_bt2_udata.found_op_data = NULL;
1428
0
        } /* end else */
1429
1430
        /* Open the index v2 B-tree */
1431
0
        if (NULL == (bt2 = H5B2_open(bt2_udata->f, bt2_udata->other_bt2_addr, NULL)))
1432
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for 'other' index");
1433
1434
        /* Set the common information for the v2 B-tree remove operation */
1435
1436
        /* Remove the record from the name index v2 B-tree */
1437
0
        if (H5B2_remove(bt2, &other_bt2_udata, NULL, NULL) < 0)
1438
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTREMOVE, H5_ITER_ERROR,
1439
0
                        "unable to remove link from 'other' index v2 B-tree");
1440
0
    } /* end if */
1441
1442
    /* Replace open objects' names */
1443
0
    if (H5G__link_name_replace(bt2_udata->f, bt2_udata->grp_full_path_r, fh_udata.lnk) < 0)
1444
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTRENAME, FAIL, "unable to rename open objects");
1445
1446
    /* Perform the deletion action on the link */
1447
    /* (call link message "delete" callback directly: *ick* - QAK) */
1448
0
    if (H5O_link_delete(bt2_udata->f, NULL, fh_udata.lnk) < 0)
1449
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete link");
1450
1451
    /* Release the space allocated for the link */
1452
0
    H5O_msg_free(H5O_LINK_ID, fh_udata.lnk);
1453
1454
    /* Remove record from fractal heap */
1455
0
    if (H5HF_remove(bt2_udata->fheap, heap_id) < 0)
1456
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTREMOVE, FAIL, "unable to remove link from fractal heap");
1457
1458
0
done:
1459
    /* Release resources */
1460
0
    if (bt2 && H5B2_close(bt2) < 0)
1461
0
        HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for 'other' index");
1462
1463
0
    FUNC_LEAVE_NOAPI(ret_value)
1464
0
} /* end H5G__dense_remove_by_idx_bt2_cb() */
1465
1466
/*-------------------------------------------------------------------------
1467
 * Function:  H5G__dense_remove_by_idx
1468
 *
1469
 * Purpose: Remove a link from the dense storage of a group, according to
1470
 *              to the offset in an indexed order
1471
 *
1472
 * Return:  Non-negative on success/Negative on failure
1473
 *
1474
 *-------------------------------------------------------------------------
1475
 */
1476
herr_t
1477
H5G__dense_remove_by_idx(H5F_t *f, const H5O_linfo_t *linfo, H5RS_str_t *grp_full_path_r, H5_index_t idx_type,
1478
                         H5_iter_order_t order, hsize_t n)
1479
0
{
1480
0
    H5HF_t          *fheap  = NULL;       /* Fractal heap handle */
1481
0
    H5G_link_table_t ltable = {0, NULL};  /* Table of links */
1482
0
    H5B2_t          *bt2    = NULL;       /* v2 B-tree handle for index */
1483
0
    haddr_t          bt2_addr;            /* Address of v2 B-tree to use for lookup */
1484
0
    herr_t           ret_value = SUCCEED; /* Return value */
1485
1486
0
    FUNC_ENTER_PACKAGE
1487
1488
    /*
1489
     * Check arguments.
1490
     */
1491
0
    assert(f);
1492
0
    assert(linfo);
1493
1494
    /* Determine the address of the index to use */
1495
0
    if (idx_type == H5_INDEX_NAME) {
1496
        /* Since names are hashed, getting them in strictly increasing or
1497
         * decreasing order requires building a table and sorting it.  If
1498
         * the order is native, use the B-tree for names.
1499
         */
1500
0
        bt2_addr = HADDR_UNDEF;
1501
0
    } /* end if */
1502
0
    else {
1503
0
        assert(idx_type == H5_INDEX_CRT_ORDER);
1504
1505
        /* This address may not be defined if creation order is tracked, but
1506
         *      there's no index on it.  If there's no v2 B-tree that indexes
1507
         *      the links and the order is native, use the B-tree for names.
1508
         *      Otherwise, build a table.
1509
         */
1510
0
        bt2_addr = linfo->corder_bt2_addr;
1511
0
    } /* end else */
1512
1513
    /* If the order is native and there's no B-tree for indexing the links,
1514
     * use the B-tree for names instead of building a table to speed up the
1515
     * process.
1516
     */
1517
0
    if (order == H5_ITER_NATIVE && !H5_addr_defined(bt2_addr)) {
1518
0
        bt2_addr = linfo->name_bt2_addr;
1519
0
        assert(H5_addr_defined(bt2_addr));
1520
0
    } /* end if */
1521
1522
    /* If there is an index defined for the field, use it */
1523
0
    if (H5_addr_defined(bt2_addr)) {
1524
0
        H5G_bt2_ud_rmbi_t udata; /* User data for v2 B-tree record removal */
1525
1526
        /* Open the fractal heap */
1527
0
        if (NULL == (fheap = H5HF_open(f, linfo->fheap_addr)))
1528
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap");
1529
1530
        /* Open the index v2 B-tree */
1531
0
        if (NULL == (bt2 = H5B2_open(f, bt2_addr, NULL)))
1532
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for index");
1533
1534
        /* Set up the user data for the v2 B-tree 'remove by index' callback */
1535
0
        udata.f               = f;
1536
0
        udata.fheap           = fheap;
1537
0
        udata.idx_type        = idx_type;
1538
0
        udata.other_bt2_addr  = idx_type == H5_INDEX_NAME ? linfo->corder_bt2_addr : linfo->name_bt2_addr;
1539
0
        udata.grp_full_path_r = grp_full_path_r;
1540
1541
        /* Remove the record from the name index v2 B-tree */
1542
0
        if (H5B2_remove_by_idx(bt2, order, n, H5G__dense_remove_by_idx_bt2_cb, &udata) < 0)
1543
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTREMOVE, FAIL, "unable to remove link from indexed v2 B-tree");
1544
0
    }      /* end if */
1545
0
    else { /* Otherwise, we need to build a table of the links and sort it */
1546
        /* Build the table of links for this group */
1547
0
        if (H5G__dense_build_table(f, linfo, idx_type, order, &ltable) < 0)
1548
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "error building table of links");
1549
1550
        /* Check for going out of bounds */
1551
0
        if (n >= ltable.nlinks)
1552
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "index out of bound");
1553
1554
        /* Remove the appropriate link from the dense storage */
1555
0
        if (H5G__dense_remove(f, linfo, grp_full_path_r, ltable.lnks[n].name) < 0)
1556
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTREMOVE, FAIL, "unable to remove link from dense storage");
1557
0
    } /* end else */
1558
1559
0
done:
1560
    /* Release resources */
1561
0
    if (fheap && H5HF_close(fheap) < 0)
1562
0
        HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap");
1563
0
    if (bt2 && H5B2_close(bt2) < 0)
1564
0
        HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for index");
1565
0
    if (ltable.lnks && H5G__link_release_table(&ltable) < 0)
1566
0
        HDONE_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link table");
1567
1568
0
    FUNC_LEAVE_NOAPI(ret_value)
1569
0
} /* end H5G__dense_remove_by_idx() */
1570
1571
/*-------------------------------------------------------------------------
1572
 * Function:  H5G__dense_delete
1573
 *
1574
 * Purpose: Delete the dense storage for a group
1575
 *
1576
 * Return:  Non-negative on success/Negative on failure
1577
 *
1578
 *-------------------------------------------------------------------------
1579
 */
1580
herr_t
1581
H5G__dense_delete(H5F_t *f, H5O_linfo_t *linfo, bool adj_link)
1582
0
{
1583
0
    herr_t ret_value = SUCCEED; /* Return value */
1584
1585
0
    FUNC_ENTER_PACKAGE
1586
1587
    /*
1588
     * Check arguments.
1589
     */
1590
0
    assert(f);
1591
0
    assert(linfo);
1592
1593
    /* Check if we are to adjust the ref. count for all the links */
1594
    /* (we adjust the ref. count when deleting a group and we _don't_ adjust
1595
     *  the ref. count when transitioning back to compact storage)
1596
     */
1597
0
    if (adj_link) {
1598
0
        H5HF_t         *fheap = NULL; /* Fractal heap handle */
1599
0
        H5G_bt2_ud_rm_t udata;        /* User data for v2 B-tree record removal */
1600
1601
        /* Open the fractal heap */
1602
0
        if (NULL == (fheap = H5HF_open(f, linfo->fheap_addr)))
1603
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap");
1604
1605
        /* Set up the user data for the v2 B-tree 'record remove' callback */
1606
0
        udata.common.f             = f;
1607
0
        udata.common.fheap         = fheap;
1608
0
        udata.common.name          = NULL;
1609
0
        udata.common.name_hash     = 0;
1610
0
        udata.common.found_op      = NULL;
1611
0
        udata.common.found_op_data = NULL;
1612
0
        udata.rem_from_fheap       = false; /* handled in "bulk" below by deleting entire heap */
1613
0
        udata.corder_bt2_addr      = linfo->corder_bt2_addr;
1614
0
        udata.grp_full_path_r      = NULL;
1615
0
        udata.replace_names        = false;
1616
1617
        /* Delete the name index, adjusting the ref. count on links removed */
1618
0
        if (H5B2_delete(f, linfo->name_bt2_addr, NULL, H5G__dense_remove_bt2_cb, &udata) < 0)
1619
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete v2 B-tree for name index");
1620
1621
        /* Close the fractal heap */
1622
0
        if (H5HF_close(fheap) < 0)
1623
0
            HGOTO_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close fractal heap");
1624
0
    } /* end if */
1625
0
    else {
1626
        /* Delete the name index, without adjusting the ref. count on the links  */
1627
0
        if (H5B2_delete(f, linfo->name_bt2_addr, NULL, NULL, NULL) < 0)
1628
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete v2 B-tree for name index");
1629
0
    } /* end else */
1630
0
    linfo->name_bt2_addr = HADDR_UNDEF;
1631
1632
    /* Check if we should delete the creation order index v2 B-tree */
1633
0
    if (linfo->index_corder) {
1634
        /* Delete the creation order index, without adjusting the ref. count on the links  */
1635
0
        assert(H5_addr_defined(linfo->corder_bt2_addr));
1636
0
        if (H5B2_delete(f, linfo->corder_bt2_addr, NULL, NULL, NULL) < 0)
1637
0
            HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete v2 B-tree for creation order index");
1638
0
        linfo->corder_bt2_addr = HADDR_UNDEF;
1639
0
    } /* end if */
1640
0
    else
1641
0
        assert(!H5_addr_defined(linfo->corder_bt2_addr));
1642
1643
    /* Delete the fractal heap */
1644
0
    if (H5HF_delete(f, linfo->fheap_addr) < 0)
1645
0
        HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete fractal heap");
1646
0
    linfo->fheap_addr = HADDR_UNDEF;
1647
1648
0
done:
1649
0
    FUNC_LEAVE_NOAPI(ret_value)
1650
0
} /* end H5G__dense_delete() */