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