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 : #ifndef ZARR_H
14 : #define ZARR_H
15 :
16 : #include "cpl_compressor.h"
17 : #include "cpl_json.h"
18 : #include "gdal_priv.h"
19 : #include "gdal_pam_multidim.h"
20 : #include "memmultidim.h"
21 :
22 : #include <array>
23 : #include <iterator>
24 : #include <map>
25 : #include <memory>
26 : #include <mutex>
27 : #include <numeric>
28 : #include <optional>
29 : #include <set>
30 :
31 : #define ZARR_DEBUG_KEY "ZARR"
32 :
33 : #define CRS_ATTRIBUTE_NAME "_CRS"
34 :
35 : // UUID identifying the multiscales zarr convention
36 : // (https://github.com/zarr-conventions/multiscales)
37 : constexpr const char *ZARR_MULTISCALES_UUID =
38 : "d35379db-88df-4056-af3a-620245f8e347";
39 :
40 : const CPLCompressor *ZarrGetShuffleCompressor();
41 : const CPLCompressor *ZarrGetShuffleDecompressor();
42 : const CPLCompressor *ZarrGetQuantizeDecompressor();
43 : const CPLCompressor *ZarrGetTIFFDecompressor();
44 : const CPLCompressor *ZarrGetFixedScaleOffsetDecompressor();
45 :
46 : /************************************************************************/
47 : /* MultiplyElements() */
48 : /************************************************************************/
49 :
50 : /** Return the product of elements in the vector
51 : */
52 70022 : template <class T> inline T MultiplyElements(const std::vector<T> &vector)
53 : {
54 70022 : return std::reduce(vector.begin(), vector.end(), T{1},
55 70022 : std::multiplies<T>{});
56 : }
57 :
58 : /************************************************************************/
59 : /* ZarrDataset */
60 : /************************************************************************/
61 :
62 : class ZarrArray;
63 : class ZarrGroupBase;
64 :
65 : class ZarrDataset final : public GDALDataset
66 : {
67 : friend class ZarrRasterBand;
68 :
69 : std::shared_ptr<ZarrGroupBase> m_poRootGroup{};
70 : CPLStringList m_aosSubdatasets{};
71 : GDALGeoTransform m_gt{};
72 : bool m_bHasGT = false;
73 : bool m_bSpatialProjConvention = false;
74 : std::shared_ptr<GDALDimension> m_poDimX{};
75 : std::shared_ptr<GDALDimension> m_poDimY{};
76 : std::shared_ptr<ZarrArray> m_poSingleArray{};
77 :
78 : static GDALDataset *OpenMultidim(const char *pszFilename, bool bUpdateMode,
79 : CSLConstList papszOpenOptions);
80 :
81 : public:
82 : explicit ZarrDataset(const std::shared_ptr<ZarrGroupBase> &poRootGroup);
83 : ~ZarrDataset() override;
84 :
85 : CPLErr FlushCache(bool bAtClosing = false) override;
86 :
87 : static GDALDataset *Open(GDALOpenInfo *poOpenInfo);
88 : static GDALDataset *
89 : CreateMultiDimensional(const char *pszFilename,
90 : CSLConstList /*papszRootGroupOptions*/,
91 : CSLConstList /*papszOptions*/);
92 :
93 : static GDALDataset *Create(const char *pszName, int nXSize, int nYSize,
94 : int nBands, GDALDataType eType,
95 : CSLConstList papszOptions);
96 :
97 : static GDALDataset *CreateCopy(const char *, GDALDataset *, int,
98 : CSLConstList papszOptions,
99 : GDALProgressFunc pfnProgress,
100 : void *pProgressData);
101 :
102 : const char *GetMetadataItem(const char *pszName,
103 : const char *pszDomain) override;
104 : CSLConstList GetMetadata(const char *pszDomain) override;
105 :
106 : CPLErr SetMetadata(CSLConstList papszMetadata,
107 : const char *pszDomain) override;
108 :
109 : const OGRSpatialReference *GetSpatialRef() const override;
110 : CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
111 :
112 : CPLErr GetGeoTransform(GDALGeoTransform >) const override;
113 : CPLErr SetGeoTransform(const GDALGeoTransform >) override;
114 :
115 : std::shared_ptr<GDALGroup> GetRootGroup() const override;
116 :
117 : protected:
118 : CPLErr IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
119 : int nYSize, void *pData, int nBufXSize, int nBufYSize,
120 : GDALDataType eBufType, int nBandCount,
121 : BANDMAP_TYPE panBandMap, GSpacing nPixelSpace,
122 : GSpacing nLineSpace, GSpacing nBandSpace,
123 : GDALRasterIOExtraArg *psExtraArg) override;
124 :
125 : CPLErr IBuildOverviews(const char *pszResampling, int nOverviews,
126 : const int *panOverviewList, int nListBands,
127 : const int *panBandList, GDALProgressFunc pfnProgress,
128 : void *pProgressData,
129 : CSLConstList papszOptions) override;
130 : };
131 :
132 : /************************************************************************/
133 : /* ZarrRasterBand */
134 : /************************************************************************/
135 :
136 : class ZarrRasterBand final : public GDALRasterBand
137 : {
138 : friend class ZarrDataset;
139 :
140 : std::shared_ptr<GDALMDArray> m_poArray;
141 : std::string m_osViewDef{};
142 : GDALColorInterp m_eColorInterp = GCI_Undefined;
143 : std::optional<double> m_dfNoData{};
144 : std::optional<uint64_t> m_nNoDataUInt64{};
145 : std::optional<int64_t> m_nNoDataInt64{};
146 : std::optional<double> m_dfOffset{};
147 : std::optional<double> m_dfScale{};
148 : std::map<int, std::unique_ptr<GDALRasterBand>> m_oMapOverview{};
149 : std::vector<std::unique_ptr<GDALRasterBand>> m_aoOverviewOld{};
150 :
151 : protected:
152 : CPLErr IReadBlock(int nBlockXOff, int nBlockYOff, void *pData) override;
153 : CPLErr IWriteBlock(int nBlockXOff, int nBlockYOff, void *pData) override;
154 : CPLErr IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
155 : int nYSize, void *pData, int nBufXSize, int nBufYSize,
156 : GDALDataType eBufType, GSpacing nPixelSpaceBuf,
157 : GSpacing nLineSpaceBuf,
158 : GDALRasterIOExtraArg *psExtraArg) override;
159 :
160 : public:
161 : explicit ZarrRasterBand(const std::shared_ptr<GDALMDArray> &poArray,
162 : const std::string &viewDef = std::string());
163 :
164 : double GetNoDataValue(int *pbHasNoData) override;
165 : int64_t GetNoDataValueAsInt64(int *pbHasNoData) override;
166 : uint64_t GetNoDataValueAsUInt64(int *pbHasNoData) override;
167 : CPLErr SetNoDataValue(double dfNoData) override;
168 : CPLErr SetNoDataValueAsInt64(int64_t nNoData) override;
169 : CPLErr SetNoDataValueAsUInt64(uint64_t nNoData) override;
170 : double GetOffset(int *pbSuccess = nullptr) override;
171 : CPLErr SetOffset(double dfNewOffset) override;
172 : double GetScale(int *pbSuccess = nullptr) override;
173 : CPLErr SetScale(double dfNewScale) override;
174 : const char *GetUnitType() override;
175 : CPLErr SetUnitType(const char *pszNewValue) override;
176 : GDALColorInterp GetColorInterpretation() override;
177 : CPLErr SetColorInterpretation(GDALColorInterp eColorInterp) override;
178 : int GetOverviewCount() override;
179 : GDALRasterBand *GetOverview(int idx) override;
180 : };
181 :
182 : /************************************************************************/
183 : /* ZarrAttributeGroup() */
184 : /************************************************************************/
185 :
186 : class ZarrAttributeGroup
187 : {
188 : // Use a MEMGroup as a convenient container for attributes.
189 : const bool m_bContainerIsGroup;
190 : std::shared_ptr<MEMGroup> m_poGroup;
191 : bool m_bModified = false;
192 :
193 : public:
194 : explicit ZarrAttributeGroup(const std::string &osParentName,
195 : bool bContainerIsGroup);
196 :
197 : bool Close();
198 :
199 : void Init(const CPLJSONObject &obj, bool bUpdatable);
200 :
201 9654 : std::shared_ptr<GDALAttribute> GetAttribute(const std::string &osName) const
202 : {
203 9654 : return m_poGroup->GetAttribute(osName);
204 : }
205 :
206 : std::vector<std::shared_ptr<GDALAttribute>>
207 295 : GetAttributes(CSLConstList papszOptions = nullptr) const
208 : {
209 295 : return m_poGroup->GetAttributes(papszOptions);
210 : }
211 :
212 : std::shared_ptr<GDALAttribute>
213 239 : CreateAttribute(const std::string &osName,
214 : const std::vector<GUInt64> &anDimensions,
215 : const GDALExtendedDataType &oDataType,
216 : CSLConstList /* papszOptions */ = nullptr)
217 : {
218 239 : auto poAttr = m_poGroup->CreateAttribute(osName, anDimensions,
219 239 : oDataType, nullptr);
220 239 : if (poAttr)
221 : {
222 239 : m_bModified = true;
223 : }
224 239 : return poAttr;
225 : }
226 :
227 28 : bool DeleteAttribute(const std::string &osName)
228 : {
229 28 : const bool bOK = m_poGroup->DeleteAttribute(osName, nullptr);
230 28 : if (bOK)
231 : {
232 16 : m_bModified = true;
233 : }
234 28 : return bOK;
235 : }
236 :
237 4460 : void SetUpdatable(bool bUpdatable)
238 : {
239 8920 : auto attrs = m_poGroup->GetAttributes(nullptr);
240 5870 : for (auto &attr : attrs)
241 : {
242 2820 : auto memAttr = std::dynamic_pointer_cast<MEMAttribute>(attr);
243 1410 : if (memAttr)
244 1410 : memAttr->SetWritable(bUpdatable);
245 : }
246 4460 : }
247 :
248 276 : void UnsetModified()
249 : {
250 276 : m_bModified = false;
251 552 : auto attrs = m_poGroup->GetAttributes(nullptr);
252 434 : for (auto &attr : attrs)
253 : {
254 316 : auto memAttr = std::dynamic_pointer_cast<MEMAttribute>(attr);
255 158 : if (memAttr)
256 158 : memAttr->SetModified(false);
257 : }
258 276 : }
259 :
260 17339 : bool IsModified() const
261 : {
262 17339 : if (m_bModified)
263 268 : return true;
264 34142 : const auto attrs = m_poGroup->GetAttributes(nullptr);
265 20267 : for (const auto &attr : attrs)
266 : {
267 3227 : const auto memAttr = std::dynamic_pointer_cast<MEMAttribute>(attr);
268 3227 : if (memAttr && memAttr->IsModified())
269 31 : return true;
270 : }
271 17040 : return false;
272 : }
273 :
274 : CPLJSONObject Serialize() const;
275 :
276 : void ParentRenamed(const std::string &osNewParentFullName);
277 :
278 : void ParentDeleted();
279 : };
280 :
281 : /************************************************************************/
282 : /* ZarrSharedResource */
283 : /************************************************************************/
284 :
285 : class ZarrSharedResource
286 : : public std::enable_shared_from_this<ZarrSharedResource>
287 : {
288 : public:
289 : enum class ConsolidatedMetadataKind
290 : {
291 : NONE,
292 : EXTERNAL, // Zarr V2 .zmetadata
293 : INTERNAL, // Zarr V3 consolidated_metadata
294 : };
295 :
296 : private:
297 : bool m_bUpdatable = false;
298 : std::string m_osRootDirectoryName{};
299 :
300 : ConsolidatedMetadataKind m_eConsolidatedMetadataKind =
301 : ConsolidatedMetadataKind::NONE;
302 : CPLJSONObject m_oObjConsolidatedMetadata{};
303 : CPLJSONObject m_oRootAttributes{};
304 : bool m_bConsolidatedMetadataModified = false;
305 :
306 : std::shared_ptr<GDALPamMultiDim> m_poPAM{};
307 : CPLStringList m_aosOpenOptions{};
308 : std::weak_ptr<ZarrGroupBase> m_poWeakRootGroup{};
309 : std::set<std::string> m_oSetArrayInLoading{};
310 : std::map<std::string, std::shared_ptr<GDALMDArray>> m_oCacheIndexingVar{};
311 : std::string m_osKerchunkParquetPath{};
312 :
313 : explicit ZarrSharedResource(const std::string &osRootDirectoryName,
314 : bool bUpdatable);
315 :
316 : std::shared_ptr<ZarrGroupBase> OpenRootGroup();
317 : void InitConsolidatedMetadataIfNeeded();
318 :
319 : public:
320 : static std::shared_ptr<ZarrSharedResource>
321 : Create(const std::string &osRootDirectoryName, bool bUpdatable);
322 :
323 : ~ZarrSharedResource();
324 :
325 5584 : bool IsUpdatable() const
326 : {
327 5584 : return m_bUpdatable;
328 : }
329 :
330 49 : const CPLJSONObject &GetConsolidatedMetadataObj() const
331 : {
332 49 : return m_oObjConsolidatedMetadata;
333 : }
334 :
335 416 : bool IsConsolidatedMetadataEnabled() const
336 : {
337 416 : return m_eConsolidatedMetadataKind != ConsolidatedMetadataKind::NONE;
338 : }
339 :
340 364 : void EnableConsolidatedMetadata(ConsolidatedMetadataKind kind)
341 : {
342 364 : m_eConsolidatedMetadataKind = kind;
343 364 : }
344 :
345 : void SetZMetadataItem(const std::string &osFilename,
346 : const CPLJSONObject &obj);
347 :
348 : void DeleteZMetadataItemRecursive(const std::string &osFilename);
349 :
350 : void RenameZMetadataRecursive(const std::string &osOldFilename,
351 : const std::string &osNewFilename);
352 :
353 2588 : const std::shared_ptr<GDALPamMultiDim> &GetPAM()
354 : {
355 2588 : return m_poPAM;
356 : }
357 :
358 13 : const std::string &GetRootDirectoryName() const
359 : {
360 13 : return m_osRootDirectoryName;
361 : }
362 :
363 3087 : const CPLStringList &GetOpenOptions() const
364 : {
365 3087 : return m_aosOpenOptions;
366 : }
367 :
368 1690 : void SetOpenOptions(CSLConstList papszOpenOptions)
369 : {
370 1690 : m_aosOpenOptions = papszOpenOptions;
371 1690 : }
372 :
373 : void
374 : UpdateDimensionSize(const std::shared_ptr<GDALDimension> &poUpdatedDim);
375 :
376 : std::shared_ptr<ZarrGroupBase> GetRootGroup();
377 :
378 108 : const std::string &GetKerchunkParquetPath() const
379 : {
380 108 : return m_osKerchunkParquetPath;
381 : }
382 :
383 114 : void SetRootGroup(const std::shared_ptr<ZarrGroupBase> &poRootGroup)
384 : {
385 114 : m_poWeakRootGroup = poRootGroup;
386 114 : }
387 :
388 : bool AddArrayInLoading(const std::string &osZarrayFilename);
389 : void RemoveArrayInLoading(const std::string &osZarrayFilename);
390 :
391 : struct SetFilenameAdder
392 : {
393 : std::shared_ptr<ZarrSharedResource> m_poSharedResource;
394 : const std::string m_osFilename;
395 : const bool m_bOK;
396 :
397 2127 : SetFilenameAdder(
398 : const std::shared_ptr<ZarrSharedResource> &poSharedResource,
399 : const std::string &osFilename)
400 2127 : : m_poSharedResource(poSharedResource), m_osFilename(osFilename),
401 2127 : m_bOK(m_poSharedResource->AddArrayInLoading(m_osFilename))
402 : {
403 2127 : }
404 :
405 2127 : ~SetFilenameAdder()
406 2127 : {
407 2127 : if (m_bOK)
408 2125 : m_poSharedResource->RemoveArrayInLoading(m_osFilename);
409 2127 : }
410 :
411 2127 : bool ok() const
412 : {
413 2127 : return m_bOK;
414 : }
415 : };
416 :
417 8 : void RegisterIndexingVariable(const std::string &osDimName,
418 : const std::shared_ptr<GDALMDArray> &poVar)
419 : {
420 8 : m_oCacheIndexingVar[osDimName] = poVar;
421 8 : }
422 : };
423 :
424 : /************************************************************************/
425 : /* ZarrGroup */
426 : /************************************************************************/
427 :
428 : class ZarrArray;
429 : class ZarrDimension;
430 :
431 : class ZarrGroupBase CPL_NON_FINAL : public GDALGroup
432 : {
433 : protected:
434 : friend class ZarrV2Group;
435 : friend class ZarrV3Group;
436 :
437 : // For ZarrV2, this is the directory of the group
438 : // For ZarrV3, this is the root directory of the dataset
439 : std::shared_ptr<ZarrSharedResource> m_poSharedResource;
440 : std::string m_osDirectoryName{};
441 : std::weak_ptr<ZarrGroupBase>
442 : m_poParent{}; // weak reference to owning parent
443 : std::shared_ptr<ZarrGroupBase>
444 : m_poParentStrongRef{}; // strong reference, used only when opening from
445 : // a subgroup
446 : mutable std::map<CPLString, std::shared_ptr<ZarrGroupBase>> m_oMapGroups{};
447 : mutable std::map<CPLString, std::shared_ptr<ZarrArray>> m_oMapMDArrays{};
448 : mutable std::map<CPLString, std::shared_ptr<ZarrDimension>>
449 : m_oMapDimensions{};
450 : mutable bool m_bDirectoryExplored = false;
451 : mutable std::set<std::string> m_oSetGroupNames{};
452 : mutable std::vector<std::string> m_aosGroups{};
453 : mutable std::set<std::string> m_oSetArrayNames{};
454 : mutable std::vector<std::string> m_aosArrays{};
455 : mutable ZarrAttributeGroup m_oAttrGroup;
456 : mutable bool m_bAttributesLoaded = false;
457 : bool m_bReadFromConsolidatedMetadata = false;
458 : mutable bool m_bDimensionsInstantiated = false;
459 : bool m_bUpdatable = false;
460 : bool m_bDimSizeInUpdate = false;
461 :
462 : virtual void ExploreDirectory() const = 0;
463 : virtual void LoadAttributes() const = 0;
464 :
465 2544 : ZarrGroupBase(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
466 : const std::string &osParentName, const std::string &osName)
467 2544 : : GDALGroup(osParentName, osName), m_poSharedResource(poSharedResource),
468 2544 : m_oAttrGroup(m_osFullName, /*bContainerIsGroup=*/true)
469 : {
470 2544 : }
471 :
472 : protected:
473 : friend class ZarrDimension;
474 : bool RenameDimension(const std::string &osOldName,
475 : const std::string &osNewName);
476 :
477 : void NotifyChildrenOfRenaming() override;
478 :
479 : void NotifyChildrenOfDeletion() override;
480 :
481 : public:
482 : ~ZarrGroupBase() override;
483 :
484 : virtual bool Close();
485 :
486 : bool Flush();
487 :
488 : std::shared_ptr<GDALAttribute>
489 458 : GetAttribute(const std::string &osName) const override
490 : {
491 458 : LoadAttributes();
492 458 : return m_oAttrGroup.GetAttribute(osName);
493 : }
494 :
495 : std::vector<std::shared_ptr<GDALAttribute>>
496 48 : GetAttributes(CSLConstList papszOptions = nullptr) const override
497 : {
498 48 : LoadAttributes();
499 48 : return m_oAttrGroup.GetAttributes(papszOptions);
500 : }
501 :
502 : std::shared_ptr<GDALAttribute>
503 : CreateAttribute(const std::string &osName,
504 : const std::vector<GUInt64> &anDimensions,
505 : const GDALExtendedDataType &oDataType,
506 : CSLConstList papszOptions = nullptr) override;
507 :
508 : bool DeleteAttribute(const std::string &osName,
509 : CSLConstList papszOptions = nullptr) override;
510 :
511 : std::vector<std::shared_ptr<GDALDimension>>
512 : GetDimensions(CSLConstList papszOptions = nullptr) const override;
513 :
514 : std::shared_ptr<GDALDimension>
515 : CreateDimension(const std::string &osName, const std::string &osType,
516 : const std::string &osDirection, GUInt64 nSize,
517 : CSLConstList papszOptions = nullptr) override;
518 :
519 : std::vector<std::string>
520 : GetMDArrayNames(CSLConstList papszOptions = nullptr) const override;
521 :
522 : std::vector<std::string>
523 : GetGroupNames(CSLConstList papszOptions = nullptr) const override;
524 :
525 : virtual std::shared_ptr<ZarrGroupBase>
526 : OpenZarrGroup(const std::string &osName,
527 : CSLConstList papszOptions = nullptr) const = 0;
528 :
529 : std::shared_ptr<GDALGroup>
530 1394 : OpenGroup(const std::string &osName,
531 : CSLConstList papszOptions = nullptr) const override
532 : {
533 : return std::static_pointer_cast<GDALGroup>(
534 1394 : OpenZarrGroup(osName, papszOptions));
535 : }
536 :
537 : bool DeleteGroup(const std::string &osName,
538 : CSLConstList papszOptions = nullptr) override;
539 :
540 : std::shared_ptr<GDALMDArray>
541 2285 : OpenMDArray(const std::string &osName,
542 : CSLConstList papszOptions = nullptr) const override
543 : {
544 : return std::static_pointer_cast<GDALMDArray>(
545 2285 : OpenZarrArray(osName, papszOptions));
546 : }
547 :
548 : bool DeleteMDArray(const std::string &osName,
549 : CSLConstList papszOptions = nullptr) override;
550 :
551 : virtual std::shared_ptr<ZarrArray>
552 : OpenZarrArray(const std::string &osName,
553 : CSLConstList papszOptions = nullptr) const = 0;
554 :
555 1045 : void SetDirectoryName(const std::string &osDirectoryName)
556 : {
557 1045 : m_osDirectoryName = osDirectoryName;
558 1045 : }
559 :
560 9 : const std::string &GetDirectoryName() const
561 : {
562 9 : return m_osDirectoryName;
563 : }
564 :
565 : void RegisterArray(const std::shared_ptr<ZarrArray> &array) const;
566 :
567 2538 : void SetUpdatable(bool bUpdatable)
568 : {
569 2538 : m_bUpdatable = bUpdatable;
570 2538 : }
571 :
572 : void UpdateDimensionSize(const std::shared_ptr<GDALDimension> &poDim);
573 :
574 : static bool IsValidObjectName(const std::string &osName);
575 :
576 : bool Rename(const std::string &osNewName) override;
577 :
578 : //! Returns false in case of error
579 : bool
580 : CheckArrayOrGroupWithSameNameDoesNotExist(const std::string &osName) const;
581 :
582 : void ParentRenamed(const std::string &osNewParentFullName) override;
583 :
584 : void NotifyArrayRenamed(const std::string &osOldName,
585 : const std::string &osNewName);
586 :
587 : //! Return the group owning the array. Might be nullptr
588 : std::shared_ptr<ZarrGroupBase> GetParentGroup() const;
589 :
590 4623 : std::shared_ptr<ZarrGroupBase> Self() const
591 : {
592 4623 : return std::dynamic_pointer_cast<ZarrGroupBase>(m_pSelf.lock());
593 : }
594 :
595 2937 : const ZarrAttributeGroup &GetAttributeGroup() const
596 : {
597 2937 : return m_oAttrGroup;
598 : }
599 : };
600 :
601 : /************************************************************************/
602 : /* ZarrV2Group */
603 : /************************************************************************/
604 :
605 : class ZarrV2Group final : public ZarrGroupBase
606 : {
607 : void ExploreDirectory() const override;
608 : void LoadAttributes() const override;
609 :
610 : std::shared_ptr<ZarrV2Group>
611 : GetOrCreateSubGroup(const std::string &osSubGroupFullname);
612 :
613 893 : ZarrV2Group(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
614 : const std::string &osParentName, const std::string &osName)
615 893 : : ZarrGroupBase(poSharedResource, osParentName, osName)
616 : {
617 893 : }
618 :
619 : bool Close() override;
620 :
621 : public:
622 : static std::shared_ptr<ZarrV2Group>
623 : Create(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
624 : const std::string &osParentName, const std::string &osName);
625 :
626 : ~ZarrV2Group() override;
627 :
628 : static std::shared_ptr<ZarrV2Group>
629 : CreateOnDisk(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
630 : const std::string &osParentName, const std::string &osName,
631 : const std::string &osDirectoryName);
632 :
633 : std::shared_ptr<ZarrArray>
634 : OpenZarrArray(const std::string &osName,
635 : CSLConstList papszOptions = nullptr) const override;
636 :
637 : std::shared_ptr<ZarrGroupBase>
638 : OpenZarrGroup(const std::string &osName,
639 : CSLConstList papszOptions = nullptr) const override;
640 :
641 : std::shared_ptr<GDALGroup>
642 : CreateGroup(const std::string &osName,
643 : CSLConstList papszOptions = nullptr) override;
644 :
645 : std::shared_ptr<ZarrArray>
646 : LoadArray(const std::string &osArrayName,
647 : const std::string &osZarrayFilename, const CPLJSONObject &oRoot,
648 : bool bLoadedFromZMetadata,
649 : const CPLJSONObject &oAttributes) const;
650 :
651 : std::shared_ptr<GDALMDArray> CreateMDArray(
652 : const std::string &osName,
653 : const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
654 : const GDALExtendedDataType &oDataType,
655 : CSLConstList papszOptions = nullptr) override;
656 :
657 : void InitFromConsolidatedMetadata(const CPLJSONObject &oRoot);
658 :
659 : bool InitFromZGroup(const CPLJSONObject &oRoot);
660 : };
661 :
662 : /************************************************************************/
663 : /* ZarrV3Group */
664 : /************************************************************************/
665 :
666 : class ZarrV3Group final : public ZarrGroupBase
667 : {
668 : bool m_bFileHasBeenWritten = false;
669 :
670 : void ExploreDirectory() const override;
671 : void LoadAttributes() const override;
672 :
673 : ZarrV3Group(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
674 : const std::string &osParentName, const std::string &osName,
675 : const std::string &osDirectoryName);
676 :
677 : std::shared_ptr<ZarrV3Group>
678 : GetOrCreateSubGroup(const std::string &osSubGroupFullname);
679 :
680 : bool Close() override;
681 :
682 : public:
683 : ~ZarrV3Group() override;
684 :
685 : static std::shared_ptr<ZarrV3Group>
686 : Create(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
687 : const std::string &osParentName, const std::string &osName,
688 : const std::string &osDirectoryName);
689 :
690 : std::shared_ptr<ZarrArray>
691 : OpenZarrArray(const std::string &osName,
692 : CSLConstList papszOptions = nullptr) const override;
693 :
694 : std::shared_ptr<ZarrGroupBase>
695 : OpenZarrGroup(const std::string &osName,
696 : CSLConstList papszOptions = nullptr) const override;
697 :
698 : static std::shared_ptr<ZarrV3Group>
699 : CreateOnDisk(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
700 : const std::string &osParentFullName, const std::string &osName,
701 : const std::string &osDirectoryName);
702 :
703 : std::shared_ptr<GDALGroup>
704 : CreateGroup(const std::string &osName,
705 : CSLConstList papszOptions = nullptr) override;
706 :
707 : std::shared_ptr<ZarrArray> LoadArray(const std::string &osArrayName,
708 : const std::string &osZarrayFilename,
709 : const CPLJSONObject &oRoot) const;
710 :
711 : void GenerateMultiscalesMetadata(const char *pszResampling = nullptr);
712 :
713 : std::shared_ptr<GDALMDArray> CreateMDArray(
714 : const std::string &osName,
715 : const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
716 : const GDALExtendedDataType &oDataType,
717 : CSLConstList papszOptions = nullptr) override;
718 :
719 723 : void SetExplored()
720 : {
721 723 : m_bDirectoryExplored = true;
722 723 : }
723 :
724 : void
725 : InitFromConsolidatedMetadata(const CPLJSONObject &oConsolidatedMetadata,
726 : const CPLJSONObject &oRootAttributes);
727 : };
728 :
729 : /************************************************************************/
730 : /* ZarrDimension */
731 : /************************************************************************/
732 :
733 : class ZarrDimension final : public GDALDimensionWeakIndexingVar
734 : {
735 : const bool m_bUpdatable;
736 : std::weak_ptr<ZarrGroupBase> m_poParentGroup;
737 : bool m_bModified = false;
738 : bool m_bXArrayDim = false;
739 :
740 : public:
741 5584 : ZarrDimension(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
742 : const std::weak_ptr<ZarrGroupBase> &poParentGroup,
743 : const std::string &osParentName, const std::string &osName,
744 : const std::string &osType, const std::string &osDirection,
745 : GUInt64 nSize)
746 5584 : : GDALDimensionWeakIndexingVar(osParentName, osName, osType,
747 : osDirection, nSize),
748 5584 : m_bUpdatable(poSharedResource->IsUpdatable()),
749 11168 : m_poParentGroup(poParentGroup)
750 : {
751 5584 : }
752 :
753 : bool Rename(const std::string &osNewName) override;
754 :
755 11336 : bool IsModified() const
756 : {
757 11336 : return m_bModified;
758 : }
759 :
760 1890 : void SetXArrayDimension()
761 : {
762 1890 : m_bXArrayDim = true;
763 1890 : }
764 :
765 16533 : bool IsXArrayDimension() const
766 : {
767 16533 : return m_bXArrayDim;
768 : }
769 : };
770 :
771 : /************************************************************************/
772 : /* DtypeElt() */
773 : /************************************************************************/
774 :
775 : struct DtypeElt
776 : {
777 : enum class NativeType
778 : {
779 : BOOLEAN,
780 : UNSIGNED_INT,
781 : SIGNED_INT,
782 : IEEEFP,
783 : COMPLEX_IEEEFP,
784 : STRING_ASCII,
785 : STRING_UNICODE
786 : };
787 :
788 : NativeType nativeType = NativeType::BOOLEAN;
789 : size_t nativeOffset = 0;
790 : size_t nativeSize = 0;
791 : bool needByteSwapping = false;
792 : bool gdalTypeIsApproxOfNative = false;
793 : GDALExtendedDataType gdalType = GDALExtendedDataType::Create(GDT_Unknown);
794 : size_t gdalOffset = 0;
795 : size_t gdalSize = 0;
796 : };
797 :
798 : /************************************************************************/
799 : /* ZarrByteVectorQuickResize */
800 : /************************************************************************/
801 :
802 : /* std::vector<GByte> with quick resizing (ie that doesn't zero out when
803 : * growing back to a previously reached greater size).
804 : */
805 186443 : class ZarrByteVectorQuickResize
806 : {
807 : std::vector<GByte> m_oVec{};
808 : size_t m_nSize = 0;
809 :
810 : public:
811 117529 : ZarrByteVectorQuickResize() = default;
812 :
813 : ZarrByteVectorQuickResize(const ZarrByteVectorQuickResize &) = delete;
814 : ZarrByteVectorQuickResize &
815 : operator=(const ZarrByteVectorQuickResize &) = delete;
816 :
817 68853 : ZarrByteVectorQuickResize(ZarrByteVectorQuickResize &&) = default;
818 : ZarrByteVectorQuickResize &
819 : operator=(ZarrByteVectorQuickResize &&) = default;
820 :
821 222957 : void resize(size_t nNewSize)
822 : {
823 222957 : if (nNewSize > m_oVec.size())
824 69112 : m_oVec.resize(nNewSize);
825 222957 : m_nSize = nNewSize;
826 222957 : }
827 :
828 1605 : inline void clear()
829 : {
830 1605 : m_nSize = 0;
831 1605 : }
832 :
833 154 : inline std::vector<GByte>::iterator begin()
834 : {
835 154 : return m_oVec.begin();
836 : }
837 :
838 1190 : inline std::vector<GByte>::const_iterator begin() const
839 : {
840 1190 : return m_oVec.begin();
841 : }
842 :
843 1032 : inline std::vector<GByte>::iterator end()
844 : {
845 1032 : return m_oVec.begin() + m_nSize;
846 : }
847 :
848 184 : inline std::vector<GByte>::const_iterator end() const
849 : {
850 184 : return m_oVec.begin() + m_nSize;
851 : }
852 :
853 : template <class InputIt>
854 : inline std::vector<GByte>::iterator
855 878 : insert(std::vector<GByte>::const_iterator pos, InputIt first, InputIt last)
856 : {
857 878 : const size_t nCount = std::distance(first, last);
858 878 : const auto &oVec = m_oVec;
859 878 : const size_t nStart = std::distance(oVec.begin(), pos);
860 878 : if (nStart == m_nSize && nStart + nCount <= m_oVec.size())
861 : {
862 : // Insert at end of user-visible vector, but fully inside the
863 : // container vector. We can just copy
864 592 : std::copy(first, last, m_oVec.begin() + nStart);
865 592 : m_nSize += nCount;
866 592 : return m_oVec.begin() + nStart;
867 : }
868 : else
869 : {
870 : // Generic case
871 286 : auto ret = m_oVec.insert(pos, first, last);
872 286 : m_nSize += nCount;
873 286 : return ret;
874 : }
875 : }
876 :
877 295291 : inline bool empty() const
878 : {
879 295291 : return m_nSize == 0;
880 : }
881 :
882 257516 : inline size_t size() const
883 : {
884 257516 : return m_nSize;
885 : }
886 :
887 47161 : inline size_t capacity() const
888 : {
889 : // Not a typo: the capacity of this object is the size
890 : // of the underlying std::vector
891 47161 : return m_oVec.size();
892 : }
893 :
894 162962 : inline GByte *data()
895 : {
896 162962 : return m_oVec.data();
897 : }
898 :
899 64978 : inline const GByte *data() const
900 : {
901 64978 : return m_oVec.data();
902 : }
903 :
904 1951 : inline GByte operator[](size_t idx) const
905 : {
906 1951 : return m_oVec[idx];
907 : }
908 :
909 60818 : inline GByte &operator[](size_t idx)
910 : {
911 60818 : return m_oVec[idx];
912 : }
913 : };
914 :
915 : /************************************************************************/
916 : /* ZarrArray */
917 : /************************************************************************/
918 :
919 : class ZarrArray CPL_NON_FINAL : public GDALPamMDArray
920 : {
921 : protected:
922 : std::shared_ptr<ZarrSharedResource> m_poSharedResource;
923 :
924 : //! weak reference to owning parent
925 : std::weak_ptr<ZarrGroupBase> m_poParent{};
926 :
927 : const std::vector<std::shared_ptr<GDALDimension>> m_aoDims;
928 : const GDALExtendedDataType m_oType;
929 :
930 : //! Array (several in case of compound data type) of native Zarr data types
931 : const std::vector<DtypeElt> m_aoDtypeElts;
932 :
933 : /** m_anOuterBlockSize is the chunk_size at the Zarr array level, which
934 : * determines the files/objects
935 : */
936 : const std::vector<GUInt64> m_anOuterBlockSize;
937 :
938 : /** m_anInnerBlockSize is the inner most block size of sharding, which
939 : * is the one exposed to the user with GetBlockSize()
940 : * When no sharding is involved m_anOuterBlockSize == m_anInnerBlockSize
941 : * Note that m_anOuterBlockSize might be equal to m_anInnerBlockSize, even
942 : * when sharding is involved, and it is actually a common use case.
943 : */
944 : const std::vector<GUInt64> m_anInnerBlockSize;
945 :
946 : /** m_anCountInnerBlockInOuter[i] = m_anOuterBlockSize[i] / m_anInnerBlockSize[i]
947 : * That is the number of inner blocks in one outer block
948 : */
949 : const std::vector<GUInt64> m_anCountInnerBlockInOuter;
950 :
951 : //! Total number of inner chunks in the array
952 : const uint64_t m_nTotalInnerChunkCount;
953 :
954 : //! Size in bytes of a inner chunk using the Zarr native data type
955 : const size_t m_nInnerBlockSizeBytes;
956 :
957 : mutable ZarrAttributeGroup m_oAttrGroup;
958 :
959 : const bool m_bUseOptimizedCodePaths;
960 :
961 : CPLStringList m_aosStructuralInfo{};
962 : CPLJSONObject m_dtype{};
963 : GByte *m_pabyNoData = nullptr;
964 : std::string m_osDimSeparator{"."};
965 : std::string m_osFilename{};
966 : mutable ZarrByteVectorQuickResize m_abyRawBlockData{};
967 : mutable ZarrByteVectorQuickResize m_abyDecodedBlockData{};
968 :
969 : /** Inner block index of the cached block
970 : * i.e. m_anCachedBlockIndices[i] < cpl::round_up(m_aoDims[i]->GetSize, m_anInnerBlockSize[i])
971 : */
972 : mutable std::vector<uint64_t> m_anCachedBlockIndices{};
973 :
974 : mutable bool m_bCachedBlockValid = false;
975 : mutable bool m_bCachedBlockEmpty = false;
976 : mutable bool m_bDirtyBlock = false;
977 : mutable std::shared_ptr<OGRSpatialReference> m_poSRS{};
978 : mutable bool m_bAllocateWorkingBuffersDone = false;
979 : mutable bool m_bWorkingBuffersOK = false;
980 : bool m_bUpdatable = false;
981 : bool m_bDefinitionModified = false;
982 : bool m_bSRSModified = false;
983 : bool m_bNew = false;
984 : std::string m_osUnit{};
985 : bool m_bUnitModified = false;
986 : double m_dfOffset = 0.0;
987 : bool m_bHasOffset = false;
988 : bool m_bOffsetModified = false;
989 : double m_dfScale = 1.0;
990 : bool m_bHasScale = false;
991 : bool m_bScaleModified = false;
992 : std::weak_ptr<ZarrGroupBase> m_poGroupWeak{};
993 : mutable bool m_bHasTriedBlockCachePresenceArray = false;
994 : mutable std::shared_ptr<GDALMDArray> m_poBlockCachePresenceArray{};
995 : mutable std::mutex m_oMutex{};
996 : CPLStringList m_aosCreationOptions{};
997 :
998 : // Value of CRS_ATTRIBUTE_NAME attribute before removing it from m_oAttrGroup
999 : CPLJSONObject m_oCRSAttribute{};
1000 :
1001 : struct CachedBlock
1002 : {
1003 : ZarrByteVectorQuickResize abyDecoded{};
1004 : };
1005 :
1006 : mutable std::map<std::vector<uint64_t>, CachedBlock> m_oChunkCache{};
1007 :
1008 : //! Region covered by the last IAdviseRead (for subset check in IRead)
1009 : mutable std::vector<GUInt64> m_anCachedAdviseReadStart{};
1010 : mutable std::vector<size_t> m_anCachedAdviseReadCount{};
1011 :
1012 : static uint64_t
1013 : ComputeBlockCount(const std::string &osName,
1014 : const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
1015 : const std::vector<GUInt64> &anBlockSize);
1016 :
1017 : ZarrArray(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
1018 : const std::shared_ptr<ZarrGroupBase> &poParent,
1019 : const std::string &osName,
1020 : const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
1021 : const GDALExtendedDataType &oType,
1022 : const std::vector<DtypeElt> &aoDtypeElts,
1023 : const std::vector<GUInt64> &anOuterBlockSize,
1024 : const std::vector<GUInt64> &anInnerBlockSize);
1025 :
1026 : virtual bool LoadBlockData(const uint64_t *blockIndices,
1027 : bool &bMissingBlockOut) const = 0;
1028 :
1029 : virtual bool AllocateWorkingBuffers() const = 0;
1030 :
1031 : void SerializeNumericNoData(CPLJSONObject &oRoot) const;
1032 :
1033 : void DeallocateDecodedBlockData();
1034 :
1035 : virtual std::string GetDataDirectory() const = 0;
1036 :
1037 : virtual CPLStringList
1038 : GetChunkIndicesFromFilename(const char *pszFilename) const = 0;
1039 :
1040 : virtual bool FlushDirtyBlock() const = 0;
1041 :
1042 : std::shared_ptr<GDALMDArray> OpenBlockPresenceCache(bool bCanCreate) const;
1043 :
1044 : void NotifyChildrenOfRenaming() override;
1045 :
1046 : void NotifyChildrenOfDeletion() override;
1047 :
1048 : static void EncodeElt(const std::vector<DtypeElt> &elts, const GByte *pSrc,
1049 : GByte *pDst);
1050 :
1051 : // Disable copy constructor and assignment operator
1052 : ZarrArray(const ZarrArray &) = delete;
1053 : ZarrArray &operator=(const ZarrArray &) = delete;
1054 :
1055 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
1056 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
1057 : const GDALExtendedDataType &bufferDataType,
1058 : void *pDstBuffer) const override;
1059 :
1060 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
1061 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
1062 : const GDALExtendedDataType &bufferDataType,
1063 : const void *pSrcBuffer) override;
1064 :
1065 : bool IsEmptyBlock(const ZarrByteVectorQuickResize &abyBlock) const;
1066 :
1067 : bool IAdviseReadCommon(const GUInt64 *arrayStartIdx, const size_t *count,
1068 : CSLConstList papszOptions,
1069 : std::vector<uint64_t> &anIndicesCur,
1070 : int &nThreadsMax,
1071 : std::vector<uint64_t> &anReqBlocksIndices,
1072 : size_t &nReqBlocks) const;
1073 :
1074 : CPLJSONObject SerializeSpecialAttributes();
1075 :
1076 : virtual std::string
1077 : BuildChunkFilename(const uint64_t *blockIndices) const = 0;
1078 :
1079 : bool SetStatistics(bool bApproxStats, double dfMin, double dfMax,
1080 : double dfMean, double dfStdDev, GUInt64 nValidCount,
1081 : CSLConstList papszOptions) override;
1082 :
1083 : bool IsBlockMissingFromCacheInfo(const std::string &osFilename,
1084 : const uint64_t *blockIndices) const;
1085 :
1086 : virtual CPLStringList GetRawBlockInfoInfo() const = 0;
1087 :
1088 : public:
1089 : ~ZarrArray() override;
1090 :
1091 : static bool ParseChunkSize(const CPLJSONArray &oChunks,
1092 : const GDALExtendedDataType &oType,
1093 : std::vector<GUInt64> &anBlockSize);
1094 :
1095 : static bool FillBlockSize(
1096 : const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
1097 : const GDALExtendedDataType &oDataType,
1098 : std::vector<GUInt64> &anBlockSize, CSLConstList papszOptions);
1099 :
1100 216 : bool IsWritable() const override
1101 : {
1102 216 : return m_bUpdatable;
1103 : }
1104 :
1105 4667 : const std::string &GetFilename() const override
1106 : {
1107 4667 : return m_osFilename;
1108 : }
1109 :
1110 : const std::vector<std::shared_ptr<GDALDimension>> &
1111 36741 : GetDimensions() const override
1112 : {
1113 36741 : return m_aoDims;
1114 : }
1115 :
1116 32840 : const GDALExtendedDataType &GetDataType() const override
1117 : {
1118 32840 : return m_oType;
1119 : }
1120 :
1121 877 : std::vector<GUInt64> GetBlockSize() const override
1122 : {
1123 877 : return m_anInnerBlockSize;
1124 : }
1125 :
1126 22 : CSLConstList GetStructuralInfo() const override
1127 : {
1128 22 : return m_aosStructuralInfo.List();
1129 : }
1130 :
1131 22828 : const void *GetRawNoDataValue() const override
1132 : {
1133 22828 : return m_pabyNoData;
1134 : }
1135 :
1136 87 : const std::string &GetUnit() const override
1137 : {
1138 87 : return m_osUnit;
1139 : }
1140 :
1141 : bool SetUnit(const std::string &osUnit) override;
1142 :
1143 85 : void RegisterUnit(const std::string &osUnit)
1144 : {
1145 85 : m_osUnit = osUnit;
1146 85 : }
1147 :
1148 2586 : void RegisterGroup(const std::weak_ptr<ZarrGroupBase> &group)
1149 : {
1150 2586 : m_poGroupWeak = group;
1151 2586 : }
1152 :
1153 : double GetOffset(bool *pbHasOffset,
1154 : GDALDataType *peStorageType) const override;
1155 :
1156 : double GetScale(bool *pbHasScale,
1157 : GDALDataType *peStorageType) const override;
1158 :
1159 : bool SetOffset(double dfOffset,
1160 : GDALDataType eStorageType = GDT_Unknown) override;
1161 :
1162 : bool SetScale(double dfScale,
1163 : GDALDataType eStorageType = GDT_Unknown) override;
1164 :
1165 : std::vector<std::shared_ptr<GDALMDArray>>
1166 : GetCoordinateVariables() const override;
1167 :
1168 : bool IsRegularlySpaced(double &dfStart, double &dfIncrement) const override;
1169 :
1170 : bool Resize(const std::vector<GUInt64> &anNewDimSizes,
1171 : CSLConstList) override;
1172 :
1173 4 : void RegisterOffset(double dfOffset)
1174 : {
1175 4 : m_bHasOffset = true;
1176 4 : m_dfOffset = dfOffset;
1177 4 : }
1178 :
1179 4 : void RegisterScale(double dfScale)
1180 : {
1181 4 : m_bHasScale = true;
1182 4 : m_dfScale = dfScale;
1183 4 : }
1184 :
1185 : bool SetRawNoDataValue(const void *pRawNoData) override;
1186 :
1187 : void RegisterNoDataValue(const void *);
1188 :
1189 2586 : void SetFilename(const std::string &osFilename)
1190 : {
1191 2586 : m_osFilename = osFilename;
1192 2586 : }
1193 :
1194 2586 : void SetDimSeparator(const std::string &osDimSeparator)
1195 : {
1196 2586 : m_osDimSeparator = osDimSeparator;
1197 2586 : }
1198 :
1199 : void SetAttributes(const std::shared_ptr<ZarrGroupBase> &poGroup,
1200 : CPLJSONObject &oAttributes);
1201 :
1202 74 : void SetSRS(const std::shared_ptr<OGRSpatialReference> &srs)
1203 : {
1204 74 : m_poSRS = srs;
1205 74 : }
1206 :
1207 : std::shared_ptr<GDALAttribute>
1208 78 : GetAttribute(const std::string &osName) const override
1209 : {
1210 78 : return m_oAttrGroup.GetAttribute(osName);
1211 : }
1212 :
1213 : std::vector<std::shared_ptr<GDALAttribute>>
1214 247 : GetAttributes(CSLConstList papszOptions) const override
1215 : {
1216 247 : return m_oAttrGroup.GetAttributes(papszOptions);
1217 : }
1218 :
1219 : std::shared_ptr<GDALAttribute>
1220 : CreateAttribute(const std::string &osName,
1221 : const std::vector<GUInt64> &anDimensions,
1222 : const GDALExtendedDataType &oDataType,
1223 : CSLConstList papszOptions = nullptr) override;
1224 :
1225 : bool DeleteAttribute(const std::string &osName,
1226 : CSLConstList papszOptions = nullptr) override;
1227 :
1228 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override;
1229 :
1230 : bool SetSpatialRef(const OGRSpatialReference *poSRS) override;
1231 :
1232 2586 : void SetUpdatable(bool bUpdatable)
1233 : {
1234 2586 : m_bUpdatable = bUpdatable;
1235 2586 : }
1236 :
1237 2586 : void SetDtype(const CPLJSONObject &dtype)
1238 : {
1239 2586 : m_dtype = dtype;
1240 2586 : }
1241 :
1242 566 : void SetDefinitionModified(bool bModified)
1243 : {
1244 566 : m_bDefinitionModified = bModified;
1245 566 : }
1246 :
1247 551 : void SetNew(bool bNew)
1248 : {
1249 551 : m_bNew = bNew;
1250 551 : }
1251 :
1252 : bool Rename(const std::string &osNewName) override;
1253 :
1254 : void ParentRenamed(const std::string &osNewParentFullName) override;
1255 :
1256 : virtual bool Flush() = 0;
1257 :
1258 : //! Return the group owning the array. Might be nullptr
1259 : std::shared_ptr<ZarrGroupBase> GetParentGroup() const;
1260 :
1261 : //! Return the root group. Might be nullptr
1262 2108 : std::shared_ptr<GDALGroup> GetRootGroup() const override
1263 : {
1264 2108 : return m_poSharedResource->GetRootGroup();
1265 : }
1266 :
1267 : bool GetRawBlockInfo(const uint64_t *panBlockCoordinates,
1268 : GDALMDArrayRawBlockInfo &info) const override;
1269 :
1270 : bool BlockCachePresence();
1271 :
1272 799 : void SetStructuralInfo(const char *pszKey, const char *pszValue)
1273 : {
1274 799 : m_aosStructuralInfo.SetNameValue(pszKey, pszValue);
1275 799 : }
1276 :
1277 552 : void SetCreationOptions(CSLConstList papszOptions)
1278 : {
1279 552 : m_aosCreationOptions = papszOptions;
1280 552 : }
1281 :
1282 1 : void InvalidateGeoreferencing()
1283 : {
1284 1 : m_bSRSModified = true;
1285 1 : }
1286 :
1287 : static void DecodeSourceElt(const std::vector<DtypeElt> &elts,
1288 : const GByte *pSrc, GByte *pDst);
1289 :
1290 : static void GetDimensionTypeDirection(CPLJSONObject &oAttributes,
1291 : std::string &osType,
1292 : std::string &osDirection);
1293 : };
1294 :
1295 : /************************************************************************/
1296 : /* ZarrV2Array */
1297 : /************************************************************************/
1298 :
1299 : class ZarrV2Array final : public ZarrArray
1300 : {
1301 : CPLJSONObject m_oCompressorJSon{};
1302 : const CPLCompressor *m_psCompressor = nullptr;
1303 : std::string m_osDecompressorId{};
1304 : const CPLCompressor *m_psDecompressor = nullptr;
1305 : CPLJSONArray m_oFiltersArray{}; // ZarrV2 specific
1306 : bool m_bFortranOrder = false;
1307 : mutable ZarrByteVectorQuickResize
1308 : m_abyTmpRawBlockData{}; // used for Fortran order
1309 :
1310 : ZarrV2Array(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
1311 : const std::shared_ptr<ZarrGroupBase> &poParent,
1312 : const std::string &osName,
1313 : const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
1314 : const GDALExtendedDataType &oType,
1315 : const std::vector<DtypeElt> &aoDtypeElts,
1316 : const std::vector<GUInt64> &anOuterBlockSize,
1317 : bool bFortranOrder);
1318 :
1319 : bool Serialize();
1320 :
1321 : bool LoadBlockData(const uint64_t *blockIndices, bool bUseMutex,
1322 : const CPLCompressor *psDecompressor,
1323 : ZarrByteVectorQuickResize &abyRawBlockData,
1324 : ZarrByteVectorQuickResize &abyTmpRawBlockData,
1325 : ZarrByteVectorQuickResize &abyDecodedBlockData,
1326 : bool &bMissingBlockOut) const;
1327 :
1328 : bool NeedDecodedBuffer() const;
1329 :
1330 : bool AllocateWorkingBuffers(
1331 : ZarrByteVectorQuickResize &abyRawBlockData,
1332 : ZarrByteVectorQuickResize &abyTmpRawBlockData,
1333 : ZarrByteVectorQuickResize &abyDecodedBlockData) const;
1334 :
1335 : void BlockTranspose(const ZarrByteVectorQuickResize &abySrc,
1336 : ZarrByteVectorQuickResize &abyDst, bool bDecode) const;
1337 :
1338 : // Disable copy constructor and assignment operator
1339 : ZarrV2Array(const ZarrV2Array &) = delete;
1340 : ZarrV2Array &operator=(const ZarrV2Array &) = delete;
1341 :
1342 : public:
1343 : ~ZarrV2Array() override;
1344 :
1345 : static std::shared_ptr<ZarrV2Array>
1346 : Create(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
1347 : const std::shared_ptr<ZarrGroupBase> &poParent,
1348 : const std::string &osName,
1349 : const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
1350 : const GDALExtendedDataType &oType,
1351 : const std::vector<DtypeElt> &aoDtypeElts,
1352 : const std::vector<GUInt64> &anBlockSize, bool bFortranOrder);
1353 :
1354 : void SetCompressorJson(const CPLJSONObject &oCompressor);
1355 :
1356 808 : void SetCompressorDecompressor(const std::string &osDecompressorId,
1357 : const CPLCompressor *psComp,
1358 : const CPLCompressor *psDecomp)
1359 : {
1360 808 : m_psCompressor = psComp;
1361 808 : m_osDecompressorId = osDecompressorId;
1362 808 : m_psDecompressor = psDecomp;
1363 808 : }
1364 :
1365 : void SetFilters(const CPLJSONArray &oFiltersArray);
1366 :
1367 : bool Flush() override;
1368 :
1369 : protected:
1370 : std::string GetDataDirectory() const override;
1371 :
1372 : CPLStringList
1373 : GetChunkIndicesFromFilename(const char *pszFilename) const override;
1374 :
1375 : bool FlushDirtyBlock() const override;
1376 :
1377 : std::string BuildChunkFilename(const uint64_t *blockIndices) const override;
1378 :
1379 : bool AllocateWorkingBuffers() const override;
1380 :
1381 : bool LoadBlockData(const uint64_t *blockIndices,
1382 : bool &bMissingBlockOut) const override;
1383 :
1384 : bool IAdviseRead(const GUInt64 *arrayStartIdx, const size_t *count,
1385 : CSLConstList papszOptions) const override;
1386 :
1387 : CPLStringList GetRawBlockInfoInfo() const override;
1388 : };
1389 :
1390 : /************************************************************************/
1391 : /* ZarrV3Array */
1392 : /************************************************************************/
1393 :
1394 : class ZarrV3CodecSequence;
1395 :
1396 : class ZarrV3Array final : public ZarrArray
1397 : {
1398 : bool m_bV2ChunkKeyEncoding = false;
1399 : std::unique_ptr<ZarrV3CodecSequence> m_poCodecs{};
1400 : CPLJSONArray m_oJSONCodecs{};
1401 : mutable bool m_bOverviewsLoaded = false;
1402 : mutable std::vector<std::shared_ptr<GDALMDArray>> m_apoOverviews{};
1403 :
1404 : /** Shard write cache: accumulates dirty inner chunks per shard, encodes
1405 : * each shard exactly once on FlushShardCache() (called from Flush()).
1406 : * Without this cache, FlushDirtyBlockSharded() would re-read, decode,
1407 : * overlay, re-encode, and write the entire shard for every inner chunk,
1408 : * resulting in O(N) encode cycles per shard where N = inner chunks/shard.
1409 : */
1410 : struct ShardWriteEntry
1411 : {
1412 : ZarrByteVectorQuickResize abyShardBuffer{};
1413 : std::vector<bool> abDirtyInnerChunks{};
1414 : };
1415 :
1416 : // Note: cache is unbounded - one entry per shard written. For very large
1417 : // rasters, consider adding LRU eviction in a follow-up.
1418 : mutable std::map<std::string, ShardWriteEntry> m_oShardWriteCache{};
1419 :
1420 : ZarrV3Array(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
1421 : const std::shared_ptr<ZarrGroupBase> &poParent,
1422 : const std::string &osName,
1423 : const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
1424 : const GDALExtendedDataType &oType,
1425 : const std::vector<DtypeElt> &aoDtypeElts,
1426 : const std::vector<GUInt64> &anOuterBlockSize,
1427 : const std::vector<GUInt64> &anInnerBlockSize);
1428 :
1429 : bool Serialize(const CPLJSONObject &oAttrs);
1430 :
1431 : bool NeedDecodedBuffer() const;
1432 :
1433 : bool AllocateWorkingBuffers(
1434 : ZarrByteVectorQuickResize &abyRawBlockData,
1435 : ZarrByteVectorQuickResize &abyDecodedBlockData) const;
1436 :
1437 : bool LoadBlockData(const uint64_t *blockIndices, bool bUseMutex,
1438 : ZarrV3CodecSequence *poCodecs,
1439 : ZarrByteVectorQuickResize &abyRawBlockData,
1440 : ZarrByteVectorQuickResize &abyDecodedBlockData,
1441 : bool &bMissingBlockOut) const;
1442 :
1443 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
1444 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
1445 : const GDALExtendedDataType &bufferDataType,
1446 : void *pDstBuffer) const override;
1447 :
1448 : void PreloadShardedBlocks(const GUInt64 *arrayStartIdx,
1449 : const size_t *count) const;
1450 :
1451 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
1452 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
1453 : const GDALExtendedDataType &bufferDataType,
1454 : const void *pSrcBuffer) override;
1455 :
1456 : bool WriteChunksThreadSafe(const GUInt64 *arrayStartIdx,
1457 : const size_t *count, const GInt64 *arrayStep,
1458 : const GPtrDiff_t *bufferStride,
1459 : const GDALExtendedDataType &bufferDataType,
1460 : const void *pSrcBuffer, const int iThread,
1461 : const int nThreads,
1462 : std::string &osErrorMsg) const;
1463 :
1464 : void LoadOverviews() const;
1465 :
1466 : void ReconstructCreationOptionsFromCodecs();
1467 :
1468 : public:
1469 : ~ZarrV3Array() override;
1470 :
1471 : static std::shared_ptr<ZarrV3Array>
1472 : Create(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
1473 : const std::shared_ptr<ZarrGroupBase> &poParent,
1474 : const std::string &osName,
1475 : const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
1476 : const GDALExtendedDataType &oType,
1477 : const std::vector<DtypeElt> &aoDtypeElts,
1478 : const std::vector<GUInt64> &anOuterBlockSize,
1479 : const std::vector<GUInt64> &anInnerBlockSize);
1480 :
1481 1372 : void SetIsV2ChunkKeyEncoding(bool b)
1482 : {
1483 1372 : m_bV2ChunkKeyEncoding = b;
1484 1372 : }
1485 :
1486 : void SetCodecs(const CPLJSONArray &oJSONCodecs,
1487 : std::unique_ptr<ZarrV3CodecSequence> &&poCodecs);
1488 :
1489 : bool Flush() override;
1490 :
1491 : static std::unique_ptr<ZarrV3CodecSequence>
1492 : SetupCodecs(const std::string &osArrayName, const CPLJSONArray &oCodecs,
1493 : const std::vector<GUInt64> &anOuterBlockSize,
1494 : std::vector<GUInt64> &anInnerBlockSize, DtypeElt &zarrDataType,
1495 : const std::vector<GByte> &abyNoData);
1496 : int GetOverviewCount() const override;
1497 :
1498 : std::shared_ptr<GDALMDArray> GetOverview(int idx) const override;
1499 :
1500 : CPLErr BuildOverviews(const char *pszResampling, int nOverviews,
1501 : const int *panOverviewList,
1502 : GDALProgressFunc pfnProgress, void *pProgressData,
1503 : CSLConstList papszOptions) override;
1504 :
1505 : static void
1506 : ExtractSubArrayFromLargerOne(const ZarrByteVectorQuickResize &abySrc,
1507 : const std::vector<size_t> &anSrcBlockSize,
1508 : const std::vector<size_t> &anInnerBlockSize,
1509 : const std::vector<size_t> &anInnerBlockIndices,
1510 : ZarrByteVectorQuickResize &abyChunk,
1511 : const size_t nDTSize);
1512 :
1513 : protected:
1514 : std::string GetDataDirectory() const override;
1515 :
1516 : CPLStringList
1517 : GetChunkIndicesFromFilename(const char *pszFilename) const override;
1518 :
1519 : bool AllocateWorkingBuffers() const override;
1520 :
1521 : bool FlushDirtyBlock() const override;
1522 : bool FlushDirtyBlockSharded() const;
1523 : bool FlushSingleShard(const std::string &osFilename,
1524 : ShardWriteEntry &entry) const;
1525 : bool FlushShardCache() const;
1526 :
1527 : std::string BuildChunkFilename(const uint64_t *blockIndices) const override;
1528 :
1529 : bool LoadBlockData(const uint64_t *blockIndices,
1530 : bool &bMissingBlockOut) const override;
1531 :
1532 : bool IAdviseRead(const GUInt64 *arrayStartIdx, const size_t *count,
1533 : CSLConstList papszOptions) const override;
1534 :
1535 : CPLStringList GetRawBlockInfoInfo() const override;
1536 : };
1537 :
1538 : void ZarrClearCoordinateCache();
1539 : void ZarrClearShardIndexCache();
1540 : void ZarrEraseShardIndexFromCache(const std::string &osFilename);
1541 :
1542 : #endif // ZARR_H
|