LCOV - code coverage report
Current view: top level - frmts/zarr - zarr_sharedresource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 218 238 91.6 %
Date: 2026-08-21 03:01:58 Functions: 12 12 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  Zarr driver
       5             :  * Author:   Even Rouault <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2021, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "zarr.h"
      14             : #include "vsikerchunk.h"
      15             : 
      16             : #include "cpl_json.h"
      17             : 
      18             : /************************************************************************/
      19             : /*               ZarrSharedResource::ZarrSharedResource()               */
      20             : /************************************************************************/
      21             : 
      22        2085 : ZarrSharedResource::ZarrSharedResource(const std::string &osRootDirectoryName,
      23        2085 :                                        bool bUpdatable)
      24        2085 :     : m_bUpdatable(bUpdatable)
      25             : {
      26        2085 :     m_oObjConsolidatedMetadata.Deinit();
      27             : 
      28        2085 :     m_osRootDirectoryName = osRootDirectoryName;
      29        2085 :     if (!m_osRootDirectoryName.empty() && m_osRootDirectoryName.back() == '/')
      30             :     {
      31           0 :         m_osRootDirectoryName.pop_back();
      32             :     }
      33        4170 :     m_poPAM = std::make_shared<GDALPamMultiDim>(
      34        6255 :         CPLFormFilenameSafe(m_osRootDirectoryName.c_str(), "pam", nullptr));
      35        2085 : }
      36             : 
      37             : /************************************************************************/
      38             : /*                     ZarrSharedResource::Create()                     */
      39             : /************************************************************************/
      40             : 
      41             : std::shared_ptr<ZarrSharedResource>
      42        2085 : ZarrSharedResource::Create(const std::string &osRootDirectoryName,
      43             :                            bool bUpdatable)
      44             : {
      45             :     return std::shared_ptr<ZarrSharedResource>(
      46        2085 :         new ZarrSharedResource(osRootDirectoryName, bUpdatable));
      47             : }
      48             : 
      49             : /************************************************************************/
      50             : /*              ZarrSharedResource::~ZarrSharedResource()               */
      51             : /************************************************************************/
      52             : 
      53        2085 : ZarrSharedResource::~ZarrSharedResource()
      54             : {
      55             :     // We try to clean caches at dataset closing, especially for Parquet
      56             :     // references, since closing Parquet datasets when the virtual file
      57             :     // systems are destroyed can be too late and cause crashes.
      58        2085 :     VSIKerchunkFileSystemsCleanCache();
      59             : 
      60        2085 :     if (m_bConsolidatedMetadataModified)
      61             :     {
      62         367 :         if (m_eConsolidatedMetadataKind == ConsolidatedMetadataKind::EXTERNAL)
      63             :         {
      64         124 :             CPLJSONDocument oDoc;
      65         124 :             oDoc.SetRoot(m_oObjConsolidatedMetadata);
      66         124 :             oDoc.Save(CPLFormFilenameSafe(m_osRootDirectoryName.c_str(),
      67             :                                           ".zmetadata", nullptr));
      68             :         }
      69         486 :         else if (m_eConsolidatedMetadataKind ==
      70         486 :                      ConsolidatedMetadataKind::INTERNAL &&
      71         486 :                  !cpl::starts_with(m_osRootDirectoryName, "/vsizip/"))
      72             :         {
      73         484 :             CPLJSONDocument oDoc;
      74             :             const std::string osFilename = CPLFormFilenameSafe(
      75         484 :                 m_osRootDirectoryName.c_str(), "zarr.json", nullptr);
      76         242 :             if (oDoc.Load(osFilename))
      77             :             {
      78         480 :                 oDoc.GetRoot().Set("consolidated_metadata",
      79         240 :                                    m_oObjConsolidatedMetadata);
      80         240 :                 oDoc.Save(osFilename);
      81             :             }
      82             :         }
      83             :     }
      84        2085 : }
      85             : 
      86             : /************************************************************************/
      87             : /*                 ZarrSharedResource::OpenRootGroup()                  */
      88             : /************************************************************************/
      89             : 
      90        1715 : std::shared_ptr<ZarrGroupBase> ZarrSharedResource::OpenRootGroup()
      91             : {
      92             :     // Probe zarr.json first so v3 datasets skip the v2 stat cascade.
      93             :     const std::string osZarrJsonFilename(CPLFormFilenameSafe(
      94        3430 :         m_osRootDirectoryName.c_str(), "zarr.json", nullptr));
      95             :     VSIStatBufL sStat;
      96             :     const bool bHasZarrJson =
      97        1715 :         (VSIStatL(osZarrJsonFilename.c_str(), &sStat) == 0);
      98             : 
      99        1715 :     if (!bHasZarrJson)
     100             :     {
     101             :         // Detect Kerchunk Parquet reference files before creating a v2
     102             :         // group.  Kerchunk .zmetadata has a "record_size" field that
     103             :         // regular consolidated metadata does not.
     104         601 :         if (!STARTS_WITH(m_osRootDirectoryName.c_str(), "/vsikerchunk"))
     105             :         {
     106             :             const std::string osZmetadataFilename(CPLFormFilenameSafe(
     107         564 :                 m_osRootDirectoryName.c_str(), ".zmetadata", nullptr));
     108         564 :             CPLJSONDocument oDoc;
     109             :             bool bOK;
     110             :             {
     111         564 :                 CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
     112         564 :                 bOK = oDoc.Load(osZmetadataFilename);
     113             :             }
     114         564 :             if (bOK && oDoc.GetRoot().GetObj("record_size").IsValid())
     115             :             {
     116             :                 m_osKerchunkParquetPath =
     117             :                     CPLSPrintf("%s{%s}", PARQUET_REF_FS_PREFIX,
     118           5 :                                m_osRootDirectoryName.c_str());
     119           5 :                 CPLDebugOnly("ZARR", "Opening %s",
     120             :                              m_osKerchunkParquetPath.c_str());
     121           5 :                 return nullptr;
     122             :             }
     123             :         }
     124             : 
     125        1192 :         auto poRG = ZarrV2Group::Create(shared_from_this(), std::string(), "/");
     126             :         // Prevents potential recursion
     127         596 :         m_poWeakRootGroup = poRG;
     128         596 :         poRG->SetUpdatable(m_bUpdatable);
     129         596 :         poRG->SetDirectoryName(m_osRootDirectoryName);
     130             : 
     131             :         const std::string osZarrayFilename(CPLFormFilenameSafe(
     132         596 :             m_osRootDirectoryName.c_str(), ".zarray", nullptr));
     133         596 :         const auto nErrorCount = CPLGetErrorCounter();
     134         596 :         if (VSIStatL(osZarrayFilename.c_str(), &sStat) == 0)
     135             :         {
     136         664 :             CPLJSONDocument oDoc;
     137         332 :             if (!oDoc.Load(osZarrayFilename))
     138           0 :                 return nullptr;
     139         664 :             const auto oRoot = oDoc.GetRoot();
     140         332 :             if (oRoot["_NCZARR_ARRAY"].IsValid())
     141             :             {
     142             :                 // If opening a NCZarr array, initialize its group from NCZarr
     143             :                 // metadata.
     144             :                 const std::string osGroupFilename(CPLFormFilenameSafe(
     145           3 :                     CPLGetDirnameSafe(m_osRootDirectoryName.c_str()).c_str(),
     146           3 :                     ".zgroup", nullptr));
     147           3 :                 if (VSIStatL(osGroupFilename.c_str(), &sStat) == 0)
     148             :                 {
     149           2 :                     CPLJSONDocument oDocGroup;
     150           2 :                     if (oDocGroup.Load(osGroupFilename))
     151             :                     {
     152           2 :                         if (!poRG->InitFromZGroup(oDocGroup.GetRoot()))
     153           1 :                             return nullptr;
     154             :                     }
     155             :                 }
     156             :             }
     157             :             const std::string osArrayName(
     158         662 :                 CPLGetBasenameSafe(m_osRootDirectoryName.c_str()));
     159             : 
     160         993 :             if (!poRG->LoadArray(osArrayName, osZarrayFilename, oRoot, false,
     161         993 :                                  CPLJSONObject()))
     162          39 :                 return nullptr;
     163             : 
     164         292 :             return poRG;
     165             :         }
     166         265 :         else if (CPLGetErrorCounter() > nErrorCount &&
     167           1 :                  strstr(CPLGetLastErrorMsg(),
     168             :                         "Generation of Kerchunk Parquet cache"))
     169             :         {
     170           0 :             return nullptr;
     171             :         }
     172             : 
     173             :         const std::string osZmetadataFilename(CPLFormFilenameSafe(
     174         264 :             m_osRootDirectoryName.c_str(), ".zmetadata", nullptr));
     175         528 :         if (CPLTestBool(CSLFetchNameValueDef(
     176         264 :                 GetOpenOptions(), "USE_CONSOLIDATED_METADATA",
     177         264 :                 CSLFetchNameValueDef(GetOpenOptions(), "USE_ZMETADATA",
     178         522 :                                      "YES"))) &&
     179         258 :             VSIStatL(osZmetadataFilename.c_str(), &sStat) == 0)
     180             :         {
     181         154 :             if (m_eConsolidatedMetadataKind == ConsolidatedMetadataKind::NONE)
     182             :             {
     183         154 :                 CPLJSONDocument oDoc;
     184         154 :                 if (!oDoc.Load(osZmetadataFilename))
     185           0 :                     return nullptr;
     186             : 
     187         154 :                 m_eConsolidatedMetadataKind =
     188             :                     ConsolidatedMetadataKind::EXTERNAL;
     189         154 :                 m_oObjConsolidatedMetadata = oDoc.GetRoot();
     190             :             }
     191             : 
     192         154 :             poRG->InitFromConsolidatedMetadata(m_oObjConsolidatedMetadata);
     193             : 
     194         154 :             return poRG;
     195             :         }
     196             : 
     197             :         const std::string osGroupFilename(CPLFormFilenameSafe(
     198         110 :             m_osRootDirectoryName.c_str(), ".zgroup", nullptr));
     199         110 :         if (VSIStatL(osGroupFilename.c_str(), &sStat) == 0)
     200             :         {
     201         200 :             CPLJSONDocument oDoc;
     202         100 :             if (!oDoc.Load(osGroupFilename))
     203           0 :                 return nullptr;
     204             : 
     205         100 :             if (!poRG->InitFromZGroup(oDoc.GetRoot()))
     206           3 :                 return nullptr;
     207          97 :             return poRG;
     208             :         }
     209             :     }
     210             : 
     211             :     // Zarr v3
     212        2248 :     auto poRG_V3 = ZarrV3Group::Create(shared_from_this(), std::string(), "/",
     213        4496 :                                        m_osRootDirectoryName);
     214             :     // Prevents potential recursion
     215        1124 :     m_poWeakRootGroup = poRG_V3;
     216        1124 :     poRG_V3->SetUpdatable(m_bUpdatable);
     217             : 
     218        1124 :     if (bHasZarrJson)
     219             :     {
     220        2228 :         CPLJSONDocument oDoc;
     221        1114 :         if (!oDoc.Load(osZarrJsonFilename))
     222           0 :             return nullptr;
     223        2228 :         const auto oRoot = oDoc.GetRoot();
     224        1114 :         if (oRoot.GetInteger("zarr_format") != 3)
     225             :         {
     226           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     227             :                      "Unhandled zarr_format value");
     228           0 :             return nullptr;
     229             :         }
     230             : 
     231             :         // Not yet adopted, but described at https://github.com/zarr-developers/zarr-specs/pull/309/files
     232             :         // and used for example by
     233             :         // https://s3.explorer.eopf.copernicus.eu/esa-zarr-sentinel-explorer-fra/tests-output/sentinel-2-l2a/S2B_MSIL2A_20251218T110359_N0511_R094_T32VLK_20251218T115223.zarr/measurements/reflectance/zarr.json
     234             :         const auto oConsolidatedMetadata =
     235        3342 :             oRoot.GetObj("consolidated_metadata");
     236         262 :         if (oConsolidatedMetadata.GetType() == CPLJSONObject::Type::Object &&
     237        1376 :             oConsolidatedMetadata.GetString("kind") == "inline" &&
     238         524 :             CPLTestBool(CSLFetchNameValueDef(
     239         262 :                 GetOpenOptions(), "USE_CONSOLIDATED_METADATA",
     240         262 :                 CSLFetchNameValueDef(GetOpenOptions(), "USE_ZMETADATA",
     241             :                                      "YES"))))
     242             :         {
     243         262 :             m_oRootAttributes.Deinit();
     244         262 :             if (m_eConsolidatedMetadataKind == ConsolidatedMetadataKind::NONE)
     245             :             {
     246         238 :                 CPLDebug("JSON", "Using consolidated_metadata");
     247         238 :                 m_eConsolidatedMetadataKind =
     248             :                     ConsolidatedMetadataKind::INTERNAL;
     249         238 :                 m_oObjConsolidatedMetadata = oConsolidatedMetadata;
     250         238 :                 m_oRootAttributes = oRoot.GetObj("attributes");
     251             :             }
     252             : 
     253         262 :             poRG_V3->InitFromConsolidatedMetadata(m_oObjConsolidatedMetadata,
     254         262 :                                                   m_oRootAttributes);
     255             :         }
     256             : 
     257        3342 :         const std::string osNodeType = oRoot.GetString("node_type");
     258        1114 :         if (osNodeType == "array")
     259             :         {
     260             :             const std::string osArrayName(
     261        1446 :                 CPLGetBasenameSafe(m_osRootDirectoryName.c_str()));
     262         723 :             poRG_V3->SetExplored();
     263         723 :             if (!poRG_V3->LoadArray(osArrayName, osZarrJsonFilename, oRoot))
     264          51 :                 return nullptr;
     265             : 
     266         672 :             return poRG_V3;
     267             :         }
     268         391 :         else if (osNodeType == "group")
     269             :         {
     270         391 :             return poRG_V3;
     271             :         }
     272             :         else
     273             :         {
     274           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Unhandled node_type value");
     275           0 :             return nullptr;
     276             :         }
     277             :     }
     278             : 
     279             :     // No explicit zarr.json in root directory ? Then recurse until we find
     280             :     // one.
     281          10 :     auto psDir = VSIOpenDir(m_osRootDirectoryName.c_str(), -1, nullptr);
     282          10 :     if (!psDir)
     283           9 :         return nullptr;
     284           1 :     bool bZarrJsonFound = false;
     285           1 :     while (const VSIDIREntry *psEntry = VSIGetNextDirEntry(psDir))
     286             :     {
     287           0 :         if (!VSI_ISDIR(psEntry->nMode) &&
     288           0 :             strcmp(CPLGetFilename(psEntry->pszName), "zarr.json") == 0)
     289             :         {
     290           0 :             bZarrJsonFound = true;
     291           0 :             break;
     292             :         }
     293           0 :     }
     294           1 :     VSICloseDir(psDir);
     295           1 :     if (bZarrJsonFound)
     296           0 :         return poRG_V3;
     297             : 
     298           1 :     return nullptr;
     299             : }
     300             : 
     301             : /************************************************************************/
     302             : /*                  ZarrSharedResource::GetRootGroup()                  */
     303             : /************************************************************************/
     304             : 
     305        3812 : std::shared_ptr<ZarrGroupBase> ZarrSharedResource::GetRootGroup()
     306             : {
     307        3812 :     auto poRootGroup = m_poWeakRootGroup.lock();
     308        3812 :     if (poRootGroup)
     309        2097 :         return poRootGroup;
     310        1715 :     poRootGroup = OpenRootGroup();
     311        1715 :     m_poWeakRootGroup = poRootGroup;
     312        1715 :     return poRootGroup;
     313             : }
     314             : 
     315             : /************************************************************************/
     316             : /*        ZarrSharedResource::InitConsolidatedMetadataIfNeeded()        */
     317             : /************************************************************************/
     318             : 
     319        1202 : void ZarrSharedResource::InitConsolidatedMetadataIfNeeded()
     320             : {
     321        1202 :     if (!m_oObjConsolidatedMetadata.IsValid())
     322             :     {
     323         361 :         m_oObjConsolidatedMetadata = CPLJSONObject();
     324         361 :         if (m_eConsolidatedMetadataKind == ConsolidatedMetadataKind::EXTERNAL)
     325             :         {
     326         107 :             m_oObjConsolidatedMetadata.Add("zarr_consolidated_format", 1);
     327         107 :             m_oObjConsolidatedMetadata.Add("metadata", CPLJSONObject());
     328             :         }
     329             :         else
     330             :         {
     331         254 :             m_oObjConsolidatedMetadata.Add("kind", "inline");
     332         254 :             m_oObjConsolidatedMetadata.Add("must_understand", false);
     333         254 :             m_oObjConsolidatedMetadata.Add("metadata", CPLJSONObject());
     334             :         }
     335             :     }
     336        1202 : }
     337             : 
     338             : /************************************************************************/
     339             : /*                ZarrSharedResource::SetZMetadataItem()                */
     340             : /************************************************************************/
     341             : 
     342        1484 : void ZarrSharedResource::SetZMetadataItem(const std::string &osFilename,
     343             :                                           const CPLJSONObject &obj)
     344             : {
     345        1484 :     if (m_eConsolidatedMetadataKind != ConsolidatedMetadataKind::NONE)
     346             :     {
     347        1192 :         InitConsolidatedMetadataIfNeeded();
     348             : 
     349        1192 :         CPLString osNormalizedFilename(osFilename);
     350        1192 :         osNormalizedFilename.replaceAll('\\', '/');
     351        1192 :         CPLAssert(STARTS_WITH(osNormalizedFilename.c_str(),
     352             :                               (m_osRootDirectoryName + '/').c_str()));
     353             : 
     354        1192 :         if (m_eConsolidatedMetadataKind == ConsolidatedMetadataKind::INTERNAL)
     355             :         {
     356         745 :             const auto nPos = osNormalizedFilename.rfind('/');
     357         745 :             if (nPos == std::string::npos)
     358           0 :                 return;
     359         745 :             osNormalizedFilename.resize(nPos);
     360             :         }
     361             : 
     362             :         const char *pszKey =
     363        1192 :             osNormalizedFilename.c_str() + m_osRootDirectoryName.size() + 1;
     364        1192 :         if (m_eConsolidatedMetadataKind == ConsolidatedMetadataKind::EXTERNAL ||
     365         745 :             strcmp(pszKey, "zarr.json") != 0)
     366             :         {
     367         914 :             m_bConsolidatedMetadataModified = true;
     368        1828 :             auto oMetadata = m_oObjConsolidatedMetadata["metadata"];
     369         914 :             oMetadata.DeleteNoSplitName(pszKey);
     370         914 :             oMetadata.AddNoSplitName(pszKey, obj);
     371             :         }
     372             :     }
     373             : }
     374             : 
     375             : /************************************************************************/
     376             : /*          ZarrSharedResource::DeleteZMetadataItemRecursive()          */
     377             : /************************************************************************/
     378             : 
     379          14 : void ZarrSharedResource::DeleteZMetadataItemRecursive(
     380             :     const std::string &osFilename)
     381             : {
     382          14 :     if (m_eConsolidatedMetadataKind != ConsolidatedMetadataKind::NONE)
     383             :     {
     384           6 :         InitConsolidatedMetadataIfNeeded();
     385             : 
     386           6 :         CPLString osNormalizedFilename(osFilename);
     387           6 :         osNormalizedFilename.replaceAll('\\', '/');
     388           6 :         CPLAssert(STARTS_WITH(osNormalizedFilename.c_str(),
     389             :                               (m_osRootDirectoryName + '/').c_str()));
     390             : 
     391           6 :         if (m_eConsolidatedMetadataKind == ConsolidatedMetadataKind::INTERNAL)
     392             :         {
     393           2 :             const auto nPos = osNormalizedFilename.rfind('/');
     394           2 :             if (nPos == std::string::npos)
     395           0 :                 return;
     396           2 :             osNormalizedFilename.resize(nPos);
     397             :         }
     398             : 
     399             :         const char *pszKey =
     400           6 :             osNormalizedFilename.c_str() + m_osRootDirectoryName.size() + 1;
     401           6 :         if (m_eConsolidatedMetadataKind == ConsolidatedMetadataKind::EXTERNAL ||
     402           2 :             strcmp(pszKey, "zarr.json") != 0)
     403             :         {
     404           6 :             m_bConsolidatedMetadataModified = true;
     405          18 :             auto oMetadata = m_oObjConsolidatedMetadata["metadata"];
     406          34 :             for (auto &item : oMetadata.GetChildren())
     407             :             {
     408          28 :                 if (STARTS_WITH(item.GetName().c_str(), pszKey))
     409             :                 {
     410          17 :                     oMetadata.DeleteNoSplitName(item.GetName());
     411             :                 }
     412             :             }
     413             :         }
     414             :     }
     415             : }
     416             : 
     417             : /************************************************************************/
     418             : /*            ZarrSharedResource::RenameZMetadataRecursive()            */
     419             : /************************************************************************/
     420             : 
     421          12 : void ZarrSharedResource::RenameZMetadataRecursive(
     422             :     const std::string &osOldFilename, const std::string &osNewFilename)
     423             : {
     424          12 :     if (m_eConsolidatedMetadataKind != ConsolidatedMetadataKind::NONE)
     425             :     {
     426           4 :         InitConsolidatedMetadataIfNeeded();
     427             : 
     428           8 :         CPLString osNormalizedOldFilename(osOldFilename);
     429           4 :         osNormalizedOldFilename.replaceAll('\\', '/');
     430           4 :         CPLAssert(STARTS_WITH(osNormalizedOldFilename.c_str(),
     431             :                               (m_osRootDirectoryName + '/').c_str()));
     432             : 
     433           8 :         CPLString osNormalizedNewFilename(osNewFilename);
     434           4 :         osNormalizedNewFilename.replaceAll('\\', '/');
     435           4 :         CPLAssert(STARTS_WITH(osNormalizedNewFilename.c_str(),
     436             :                               (m_osRootDirectoryName + '/').c_str()));
     437             : 
     438           4 :         m_bConsolidatedMetadataModified = true;
     439             : 
     440             :         const char *pszOldKeyRadix =
     441           4 :             osNormalizedOldFilename.c_str() + m_osRootDirectoryName.size() + 1;
     442             :         const char *pszNewKeyRadix =
     443           4 :             osNormalizedNewFilename.c_str() + m_osRootDirectoryName.size() + 1;
     444             : 
     445          12 :         auto oMetadata = m_oObjConsolidatedMetadata["metadata"];
     446          28 :         for (auto &item : oMetadata.GetChildren())
     447             :         {
     448          24 :             if (STARTS_WITH(item.GetName().c_str(), pszOldKeyRadix))
     449             :             {
     450          11 :                 oMetadata.DeleteNoSplitName(item.GetName());
     451          22 :                 std::string osNewKey(pszNewKeyRadix);
     452          11 :                 osNewKey += (item.GetName().c_str() + strlen(pszOldKeyRadix));
     453          11 :                 oMetadata.AddNoSplitName(osNewKey, item);
     454             :             }
     455             :         }
     456             :     }
     457          12 : }
     458             : 
     459             : /************************************************************************/
     460             : /*              ZarrSharedResource::UpdateDimensionSize()               */
     461             : /************************************************************************/
     462             : 
     463           7 : void ZarrSharedResource::UpdateDimensionSize(
     464             :     const std::shared_ptr<GDALDimension> &poDim)
     465             : {
     466          14 :     auto poRG = m_poWeakRootGroup.lock();
     467           7 :     if (!poRG)
     468           0 :         poRG = OpenRootGroup();
     469           7 :     if (poRG)
     470             :     {
     471           7 :         poRG->UpdateDimensionSize(poDim);
     472             :     }
     473             :     else
     474             :     {
     475           0 :         CPLError(CE_Failure, CPLE_AppDefined, "UpdateDimensionSize() failed");
     476             :     }
     477           7 :     poRG.reset();
     478           7 : }
     479             : 
     480             : /************************************************************************/
     481             : /*               ZarrSharedResource::AddArrayInLoading()                */
     482             : /************************************************************************/
     483             : 
     484        2127 : bool ZarrSharedResource::AddArrayInLoading(const std::string &osZarrayFilename)
     485             : {
     486             :     // Prevent too deep or recursive array loading
     487        2127 :     if (m_oSetArrayInLoading.find(osZarrayFilename) !=
     488        4254 :         m_oSetArrayInLoading.end())
     489             :     {
     490           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     491             :                  "Attempt at recursively loading %s", osZarrayFilename.c_str());
     492           1 :         return false;
     493             :     }
     494        2126 :     if (m_oSetArrayInLoading.size() == 32)
     495             :     {
     496           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     497             :                  "Too deep call stack in LoadArray()");
     498           1 :         return false;
     499             :     }
     500        2125 :     m_oSetArrayInLoading.insert(osZarrayFilename);
     501        2125 :     return true;
     502             : }
     503             : 
     504             : /************************************************************************/
     505             : /*              ZarrSharedResource::RemoveArrayInLoading()              */
     506             : /************************************************************************/
     507             : 
     508        2125 : void ZarrSharedResource::RemoveArrayInLoading(
     509             :     const std::string &osZarrayFilename)
     510             : {
     511        2125 :     m_oSetArrayInLoading.erase(osZarrayFilename);
     512        2125 : }

Generated by: LCOV version 1.14