Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
b6146ac
Add dispatch layer for consolidated ZARR access
mannreis Nov 18, 2024
f48bda3
Skip s3 listing until actually necessary
mannreis Nov 22, 2024
c8c7186
Resolving rebase issues
mannreis Nov 22, 2024
f915630
Use zmetadata layer
mannreis Nov 22, 2024
2388f48
Ensure no s3 listing with using consolidated metadata
mannreis Nov 22, 2024
f5757a4
Remove draft consolidated zarr3
mannreis Nov 25, 2024
2a2349e
Free zarr metadata pointer
mannreis Nov 25, 2024
05b766f
Fix memory leaks
mannreis Dec 10, 2024
f183750
Housekeeping
mannreis Dec 10, 2024
243d714
Add consolidated [nc]zarr tests with mode=file|zip
mannreis Dec 12, 2024
47259aa
Allow to define S3 endpoint for tests during build
mannreis Dec 12, 2024
a0551b6
Setup initial Zarr consolidated tests
mannreis Dec 12, 2024
7ca0658
Add more tests
mannreis Dec 17, 2024
03c786d
Fix warnings
mannreis Dec 17, 2024
c6616b6
Adjusting DEFINEs
mannreis Dec 18, 2024
16c7fb4
Removing dead code
mannreis Dec 18, 2024
c1c9c5c
NCjson make uploads take const pointer
mannreis Dec 13, 2024
7677158
Add Zarr metadata write layer
mannreis Dec 13, 2024
f672068
Add zarr consolidated write
mannreis Dec 13, 2024
1ec0605
Write .zmetadata when syncing file
mannreis Dec 17, 2024
dab936e
Fix warnings
mannreis Dec 17, 2024
93cc72b
Rebase issues
mannreis Dec 18, 2024
20b55bf
Dead code
mannreis Dec 18, 2024
5b0a940
refactor:
mannreis Nov 25, 2025
087081b
tests: remove default blosc compression from zarr dataset
mannreis Nov 25, 2025
ce2db3a
Expose ncstrndup as strndup to whole libnetcdf
mannreis Nov 25, 2025
43fa6ef
zmetadata: add consolidated json validation functions
mannreis Nov 26, 2025
c02c946
zinternal: Remove pointer to NCZ_Metadata, use struct - align with v3…
mannreis Nov 27, 2025
4edd9c1
tests: fix issue with run_consolidated_zarr
mannreis Nov 27, 2025
46f099e
netcdf.h: introduce NC_EZARRMETA for metadata errors
mannreis Nov 27, 2025
fed3b2c
refactor: rename consolidated validation function
mannreis Nov 27, 2025
01ae060
zmetadata: return NC_EZARRMETA on invalid consolidated metadata
mannreis Nov 27, 2025
439f9cf
zmetadata: fallback when unable to use consolidated metadata
mannreis Nov 27, 2025
381cc7f
tests: exercise consolidated zmetadata fallbacks in various scenarios
mannreis Nov 27, 2025
fb1756a
zinternal: directives fir default consolidated env and controls
mannreis Nov 28, 2025
02ad123
zmetadata: fix fallback scenario for non consolidated dataset
mannreis Nov 28, 2025
ba3b7b2
tests: clean fix tests - this
mannreis Nov 28, 2025
0596b4a
zmetadata: sort groups and variables lookups
mannreis Nov 28, 2025
55f65c8
Revert "Allow to define S3 endpoint for tests during build"
mannreis Nov 28, 2025
823158a
cosmetic
mannreis Dec 2, 2025
39e988d
zmetadata: use const char *key instead of NC_GRP_INFO_T
mannreis Dec 2, 2025
4dec819
zmetadata: flatten dispatch layer
mannreis Dec 2, 2025
0f994a6
zmetadata: rename `metadata_handler` to `metadata`
mannreis Dec 2, 2025
6f8f8d9
zmetadata: remove comments
mannreis Dec 2, 2025
70b4153
zmetadata: add list_nodes and use wrap it for list_groups and list_va…
mannreis Dec 2, 2025
1d5d1f3
zsync: use list_node to fetch both groups and variables at once
mannreis Dec 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions include/ncuri.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ typedef struct NCURI {
extern "C" {
#endif

#ifndef HAVE_STRNDUP
#define strndup ncstrndup
/* Not all systems have strndup, so provide one*/
char *ncstrndup(const char *s, size_t len);
#endif

EXTERNL int ncuriparse(const char* s, NCURI** ncuri);
EXTERNL void ncurifree(NCURI* ncuri);

Expand Down
4 changes: 3 additions & 1 deletion include/netcdf.h
Original file line number Diff line number Diff line change
Expand Up @@ -531,8 +531,10 @@ by the desired type. */
#define NC_EOBJECT (-140) /**< Some object exists when it should not */
#define NC_ENOOBJECT (-141) /**< Some object not found */
#define NC_EPLUGIN (-142) /**< Unclassified failure in accessing a dynamically loaded plugin> */
#define NC_ENOTZARR (-143) /**< Malformed (NC)Zarr file */
#define NC_EZARRMETA (-144) /**< Malformed (NC)Zarr file consolidated metadata */

#define NC4_LAST_ERROR (-142) /**< @internal All netCDF errors > this. */
#define NC4_LAST_ERROR (-144) /**< @internal All netCDF errors > this. */

/*
* Don't forget to update docs/all-error-codes.md if adding new error codes here!
Expand Down
1 change: 0 additions & 1 deletion libdispatch/ncuri.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ static const char* userpwdallow =
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!$&'()*+,-.;=_~?#/";

#ifndef HAVE_STRNDUP
#define strndup ncstrndup
/* Not all systems have strndup, so provide one*/
char*
ncstrndup(const char* s, size_t len)
Expand Down
3 changes: 3 additions & 0 deletions libnczarr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ zgrp.c
zinternal.c
zmap.c
zmap_file.c
zmetadata2.c
zmetadata.c
zodom.c
zopen.c
zprov.c
Expand All @@ -39,6 +41,7 @@ zdispatch.h
zincludes.h
zinternal.h
zmap.h
zmetadata.h
zodom.h
zprovenance.h
zplugins.h
Expand Down
3 changes: 3 additions & 0 deletions libnczarr/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ zgrp.c \
zinternal.c \
zmap.c \
zmap_file.c \
zmetadata2.c \
zmetadata.c \
zodom.c \
zopen.c \
zprov.c \
Expand All @@ -59,6 +61,7 @@ zdispatch.h \
zincludes.h \
zinternal.h \
zmap.h \
zmetadata.h \
zodom.h \
zprovenance.h \
zplugins.h \
Expand Down
12 changes: 12 additions & 0 deletions libnczarr/zarr.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ ncz_create_dataset(NC_FILE_INFO_T* file, NC_GRP_INFO_T* root, NClist* controls)
if((stat = nczmap_create(zinfo->controls.mapimpl,nc->path,nc->mode,zinfo->controls.flags,NULL,&zinfo->map)))
goto done;

/* Initialize metadata handle */
assert(zinfo->map != NULL);
if((stat = NCZMD_set_metadata_handler(zinfo))) goto done;

done:
ncurifree(uri);
NCJreclaim(json);
Expand Down Expand Up @@ -143,6 +147,10 @@ ncz_open_dataset(NC_FILE_INFO_T* file, NClist* controls)
if((stat = nczmap_open(zinfo->controls.mapimpl,nc->path,mode,zinfo->controls.flags,NULL,&zinfo->map)))
goto done;

/* Initialize metadata handle */
assert(zinfo->map != NULL);
NCZMD_set_metadata_handler(zinfo);

/* Ok, try to read superblock */
if((stat = ncz_read_superblock(file,&nczarr_version,&zarr_format))) goto done;

Expand Down Expand Up @@ -268,6 +276,7 @@ applycontrols(NCZ_FILE_INFO_T* zinfo)
/* Process the modelist first */
zinfo->controls.mapimpl = NCZM_DEFAULT;
zinfo->controls.flags |= FLAG_XARRAYDIMS; /* Always support XArray convention where possible */
zinfo->controls.flags |= (NCZARR_CONSOLIDATED_DEFAULT ? FLAG_CONSOLIDATED : 0); /* Default to consolidated metadata */
for(i=0;i<nclistlength(modelist);i++) {
const char* p = nclistget(modelist,i);
if(strcasecmp(p,PUREZARRCONTROL)==0)
Expand All @@ -279,6 +288,9 @@ applycontrols(NCZ_FILE_INFO_T* zinfo)
else if(strcasecmp(p,"zip")==0) zinfo->controls.mapimpl = NCZM_ZIP;
else if(strcasecmp(p,"file")==0) zinfo->controls.mapimpl = NCZM_FILE;
else if(strcasecmp(p,"s3")==0) zinfo->controls.mapimpl = NCZM_S3;
else if(strcasecmp(p,"consolidate") == 0 || strcasecmp(p,"consolidated") == 0) {
zinfo->controls.flags |= FLAG_CONSOLIDATED;
}
}
/* Apply negative controls by turning off negative flags */
/* This is necessary to avoid order dependence of mode flags when both positive and negative flags are defined */
Expand Down
2 changes: 1 addition & 1 deletion libnczarr/zarr.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ EXTERNL int NCZ_inferattrtype(const NCjson* value, nc_type typehint, nc_type* ty
EXTERNL int NCZ_inferinttype(unsigned long long u64, int negative);
EXTERNL int ncz_fill_value_sort(nc_type nctype, int*);
EXTERNL int NCZ_createobject(NCZMAP* zmap, const char* key, size64_t size);
EXTERNL int NCZ_uploadjson(NCZMAP* zmap, const char* key, NCjson* json);
EXTERNL int NCZ_uploadjson(NCZMAP* zmap, const char* key, const NCjson* json);
EXTERNL int NCZ_downloadjson(NCZMAP* zmap, const char* key, NCjson** jsonp);
EXTERNL int NCZ_subobjects(NCZMAP* map, const char* prefix, const char* tag, char dimsep, NClist* objlist);
EXTERNL int NCZ_grpname_full(int gid, char** pathp);
Expand Down
1 change: 1 addition & 0 deletions libnczarr/zclose.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ ncz_close_file(NC_FILE_INFO_T* file, int abort)
goto done;
nclistfreeall(zinfo->controllist);
NC_authfree(zinfo->auth);
NCZMD_free_metadata_handler(&(zinfo->metadata));
nullfree(zinfo);

done:
Expand Down
1 change: 1 addition & 0 deletions libnczarr/zincludes.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ extern "C" {
#include "ncutil.h"

#include "zmap.h"
#include "zmetadata.h"
#include "zinternal.h"
#include "zdispatch.h"
#include "zprovenance.h"
Expand Down
19 changes: 14 additions & 5 deletions libnczarr/zinternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#define ZINTERNAL_H

#define ZARRVERSION "2"
#define ZARRFORMAT2 2

/* NCZARRVERSION is independent of Zarr version,
but NCZARRVERSION => ZARRVERSION */
Expand All @@ -22,6 +23,11 @@
#define NCZ_CHUNKSIZE_FACTOR (10)
#define NCZ_MIN_CHUNK_SIZE (2)

/* The name of the env var for controlling .zmetadata use*/
#define NCZARR_CONSOLIDATED_KEY_ENV "NCZARR_METADATA_CONSOLIDATED_KEY"
#define NCZARR_CONSOLIDATED_ENV "NCZARR_CONSOLIDATED"
#define NCZARR_CONSOLIDATED_DEFAULT 0 /* default to consolidated metadata */

/**************************************************/
/* Constants */

Expand All @@ -38,11 +44,12 @@
# endif
#endif

#define ZMETAROOT "/.zgroup"
#define ZMETAATTR "/.zattrs"
#define ZGROUP ".zgroup"
#define ZATTRS ".zattrs"
#define ZARRAY ".zarray"
/* V2 Reserved Objects */
#define Z2METAROOT "/.zgroup"
#define Z2ATTSROOT "/.zattrs"
#define Z2GROUP ".zgroup"
#define Z2ATTRS ".zattrs"
#define Z2ARRAY ".zarray"

/* V2 Reserved Attributes */
/*
Expand Down Expand Up @@ -141,8 +148,10 @@ typedef struct NCZ_FILE_INFO {
# define FLAG_LOGGING 4
# define FLAG_XARRAYDIMS 8
# define FLAG_NCZARR_KEY 16 /* _nczarr_xxx keys are stored in object and not in _nczarr_attrs */
# define FLAG_CONSOLIDATED 32 /* Use/set consolidated metadata */
NCZM_IMPL mapimpl;
} controls;
struct NCZ_Metadata metadata;
int default_maxstrlen; /* default max str size for variables of type string */
} NCZ_FILE_INFO_T;

Expand Down
9 changes: 0 additions & 9 deletions libnczarr/zmap_s3sdk.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,15 +225,6 @@ zs3open(const char *path, int mode, size64_t flags, void* parameters, NCZMAP** m
stat = NC_ES3; goto done;
}

/* Search the root for content */
content = nclistnew();
if((stat = NC_s3sdklist(z3map->s3client,z3map->s3.bucket,z3map->s3.rootkey,&nkeys,NULL,&z3map->errmsg)))
goto done;
if(nkeys == 0) {
/* dataset does not actually exist; we choose to return ENOOBJECT instead of EEMPTY */
stat = NC_ENOOBJECT;
goto done;
}
if(mapp) *mapp = (NCZMAP*)z3map;

done:
Expand Down
161 changes: 161 additions & 0 deletions libnczarr/zmetadata.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/*********************************************************************
* Copyright 2018, UCAR/Unidata
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
*********************************************************************/

#include "zincludes.h"

static int
cmpstrings(const void* a1, const void* a2)
{
const char** s1 = (const char**)a1;
const char** s2 = (const char**)a2;
return strcmp(*s1,*s2);
}

int NCZMD_list_nodes(NCZ_FILE_INFO_T *zfile, const char * key, NClist *groups, NClist *vars)
{
int stat = NC_NOERR;
if((stat = zfile->metadata.list_nodes(zfile,key, groups, vars))){
return stat;
}
qsort(groups->content, groups->length, sizeof(char*), cmpstrings);
qsort(vars->content, vars->length, sizeof(char*), cmpstrings);
return stat;
}

int NCZMD_list_groups(NCZ_FILE_INFO_T *zfile, const char * key, NClist *subgrpnames)
{
int stat = NC_NOERR;
if((stat = zfile->metadata.list_groups(zfile,key, subgrpnames))){
return stat;
}
qsort(subgrpnames->content, subgrpnames->length, sizeof(char*), cmpstrings);
return stat;
}

int NCZMD_list_variables(NCZ_FILE_INFO_T *zfile, const char * key, NClist *varnames)
{
int stat = NC_NOERR;
if((stat = zfile->metadata.list_variables(zfile, key, varnames))){
return stat;
}
qsort(varnames->content, varnames->length, sizeof(char*), cmpstrings);
return stat;
}

int NCZMD_fetch_json_group(NCZ_FILE_INFO_T *zfile, const char *key, NCjson **jgroup) {
return zfile->metadata.fetch_json_content(zfile, NCZMD_GROUP, key, jgroup);
}

int NCZMD_fetch_json_attrs(NCZ_FILE_INFO_T *zfile, const char *key, NCjson **jattrs) {
return zfile->metadata.fetch_json_content(zfile, NCZMD_ATTRS, key, jattrs);
}

int NCZMD_fetch_json_array(NCZ_FILE_INFO_T *zfile, const char *key, NCjson **jarray) {
return zfile->metadata.fetch_json_content(zfile, NCZMD_ARRAY, key, jarray);
}

int NCZMD_update_json_group(NCZ_FILE_INFO_T *zfile, const char *key, const NCjson *jgroup) {
return zfile->metadata.update_json_content(zfile, NCZMD_GROUP, key, jgroup);
}

int NCZMD_update_json_attrs(NCZ_FILE_INFO_T *zfile, const char *key, const NCjson *jattrs) {
return zfile->metadata.update_json_content(zfile, NCZMD_ATTRS, key , jattrs);
}

int NCZMD_update_json_array(NCZ_FILE_INFO_T *zfile, const char *key, const NCjson *jarray) {
return zfile->metadata.update_json_content(zfile, NCZMD_ARRAY, key, jarray);
}

int NCZMD_consolidate(NCZ_FILE_INFO_T *zfile) {
int stat = NC_NOERR;
if (zfile->creating == 1 && zfile->metadata.jcsl !=NULL){
stat = NCZ_uploadjson(zfile->map, Z2METADATA ,zfile->metadata.jcsl);
}
return stat;
}

int NCZMD_is_metadata_consolidated(NCZ_FILE_INFO_T *zfile)
{
NCZ_Metadata *zmd = &(zfile->metadata);
if (zmd == NULL ||
zmd->jcsl == NULL ||
NCJsort(zmd->jcsl) != NCJ_DICT ||
!(zmd->flags & ZARR_CONSOLIDATED))
{
return NC_ENOOBJECT;
}
return NC_NOERR;
}

int NCZMD_get_metadata_format(NCZ_FILE_INFO_T *zfile, int *zarrformat)
{
NCZ_Metadata *zmd = &(zfile->metadata);

if (zmd->zarr_format >= ZARRFORMAT2)
{
*zarrformat = zmd->zarr_format;
return NC_NOERR;
}

if (!nczmap_exists(zfile->map, "/" Z2ATTRS) && !nczmap_exists(zfile->map, "/" Z2GROUP) && !nczmap_exists(zfile->map, "/" Z2ARRAY))
{
return NC_ENOTZARR;
}

*zarrformat = ZARRFORMAT2;
return NC_NOERR;
}


int use_consolidated_metadata(NCZ_FILE_INFO_T *zfile)
{
int use_consolidated = NCZARR_CONSOLIDATED_DEFAULT || (zfile->controls.flags & FLAG_CONSOLIDATED);
const char *e = getenv(NCZARR_CONSOLIDATED_ENV);

int env_use_consolidated = (e != NULL) && (
(atoi(e) > 0) ||(strcasecmp(e, "true") == 0) || (strcasecmp(e, "yes") == 0)
);

return use_consolidated || env_use_consolidated ;
}

int NCZMD_set_metadata_handler(NCZ_FILE_INFO_T *zfile)
{
NCjson *jcsl = NULL;

int use_consolidated = use_consolidated_metadata(zfile);
if (!use_consolidated){
nclog(NCLOGNOTE, "Not using consolidated metadata! Doing so could improve reading performance");
}

if (use_consolidated && zfile->creating) {
zfile->metadata = *NCZ_csl_metadata_handler2;
return NC_NOERR;
}

zfile->metadata = *NCZ_metadata_handler2;
if (!use_consolidated)
return NC_NOERR;

if (NCZ_downloadjson(zfile->map, Z2METADATA, &jcsl) || jcsl == NULL) {
nclog(NCLOGNOTE, "Dataset not consolidated! Doing so will improve performance");
return NC_NOERR;
}

if (NCZ_csl_metadata_handler2->validate_consolidated(jcsl) != NC_NOERR) {
nclog(NCLOGWARN,"Consolidated metadata is invalid, ignoring it!");
return NC_EZARRMETA;
}

zfile->metadata = *NCZ_csl_metadata_handler2;
zfile->metadata.jcsl = jcsl;
return NC_NOERR;
}

void NCZMD_free_metadata_handler(NCZ_Metadata * zmd){
if (zmd == NULL) return;
NCJreclaim(zmd->jcsl);
zmd->jcsl = NULL;
}
Loading
Loading