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