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