Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL TileDB Driver
4 : * Purpose: Implement GDAL TileDB Support based on https://www.tiledb.io
5 : * Author: TileDB, Inc
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2023, TileDB, Inc
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "tiledbheaders.h"
14 : #include "tiledbdrivercore.h"
15 :
16 : TileDBDataset::~TileDBDataset() = default;
17 :
18 : /************************************************************************/
19 : /* VSI_to_tiledb_uri() */
20 : /************************************************************************/
21 :
22 1830 : CPLString TileDBDataset::VSI_to_tiledb_uri(const char *pszUri)
23 : {
24 1830 : CPLString osUri;
25 :
26 1830 : if (STARTS_WITH_CI(pszUri, "/VSIS3/"))
27 0 : osUri.Printf("s3://%s", pszUri + 7);
28 1830 : else if (STARTS_WITH_CI(pszUri, "/VSIGS/"))
29 0 : osUri.Printf("gcs://%s", pszUri + 7);
30 : else
31 : {
32 1830 : osUri = pszUri;
33 : // tiledb (at least at 2.4.2 on Conda) wrongly interprets relative
34 : // directories on Windows as absolute ones.
35 1830 : if (CPLIsFilenameRelative(pszUri))
36 : {
37 863 : char *pszCurDir = CPLGetCurrentDir();
38 863 : if (pszCurDir)
39 863 : osUri = CPLFormFilenameSafe(pszCurDir, pszUri, nullptr);
40 863 : CPLFree(pszCurDir);
41 : }
42 : }
43 :
44 1830 : return osUri;
45 : }
46 :
47 : /************************************************************************/
48 : /* AddFilter() */
49 : /************************************************************************/
50 :
51 2 : CPLErr TileDBDataset::AddFilter(tiledb::Context &ctx,
52 : tiledb::FilterList &filterList,
53 : const char *pszFilterName, const int level)
54 :
55 : {
56 : try
57 : {
58 2 : if (pszFilterName == nullptr)
59 : filterList.add_filter(
60 0 : tiledb::Filter(ctx, TILEDB_FILTER_NONE)
61 0 : .set_option(TILEDB_COMPRESSION_LEVEL, level));
62 2 : else if EQUAL (pszFilterName, "GZIP")
63 : filterList.add_filter(
64 0 : tiledb::Filter(ctx, TILEDB_FILTER_GZIP)
65 0 : .set_option(TILEDB_COMPRESSION_LEVEL, level));
66 2 : else if EQUAL (pszFilterName, "ZSTD")
67 : filterList.add_filter(
68 4 : tiledb::Filter(ctx, TILEDB_FILTER_ZSTD)
69 2 : .set_option(TILEDB_COMPRESSION_LEVEL, level));
70 0 : else if EQUAL (pszFilterName, "LZ4")
71 : filterList.add_filter(
72 0 : tiledb::Filter(ctx, TILEDB_FILTER_LZ4)
73 0 : .set_option(TILEDB_COMPRESSION_LEVEL, level));
74 0 : else if EQUAL (pszFilterName, "RLE")
75 : filterList.add_filter(
76 0 : tiledb::Filter(ctx, TILEDB_FILTER_RLE)
77 0 : .set_option(TILEDB_COMPRESSION_LEVEL, level));
78 0 : else if EQUAL (pszFilterName, "BZIP2")
79 : filterList.add_filter(
80 0 : tiledb::Filter(ctx, TILEDB_FILTER_BZIP2)
81 0 : .set_option(TILEDB_COMPRESSION_LEVEL, level));
82 0 : else if EQUAL (pszFilterName, "DOUBLE-DELTA")
83 : filterList.add_filter(
84 0 : tiledb::Filter(ctx, TILEDB_FILTER_DOUBLE_DELTA));
85 0 : else if EQUAL (pszFilterName, "POSITIVE-DELTA")
86 : filterList.add_filter(
87 0 : tiledb::Filter(ctx, TILEDB_FILTER_POSITIVE_DELTA));
88 : else
89 0 : return CE_Failure;
90 :
91 2 : return CE_None;
92 : }
93 0 : catch (const tiledb::TileDBError &e)
94 : {
95 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
96 0 : return CE_Failure;
97 : }
98 : }
99 :
100 : /************************************************************************/
101 : /* Identify() */
102 : /************************************************************************/
103 :
104 45332 : int TileDBDataset::Identify(GDALOpenInfo *poOpenInfo)
105 :
106 : {
107 45332 : int nRet = TileDBDriverIdentifySimplified(poOpenInfo);
108 45322 : if (nRet == GDAL_IDENTIFY_UNKNOWN)
109 : {
110 : try
111 : {
112 2312 : tiledb::Context ctx;
113 : CPLString osArrayPath =
114 1156 : TileDBDataset::VSI_to_tiledb_uri(poOpenInfo->pszFilename);
115 1156 : const auto eType = tiledb::Object::object(ctx, osArrayPath).type();
116 1156 : nRet = (eType == tiledb::Object::Type::Array ||
117 : eType == tiledb::Object::Type::Group);
118 : }
119 0 : catch (...)
120 : {
121 0 : nRet = FALSE;
122 : }
123 : }
124 45329 : return nRet;
125 : }
126 :
127 : /************************************************************************/
128 : /* Delete() */
129 : /************************************************************************/
130 :
131 16 : CPLErr TileDBDataset::Delete(const char *pszFilename)
132 :
133 : {
134 : try
135 : {
136 32 : tiledb::Context ctx;
137 32 : tiledb::VFS vfs(ctx);
138 32 : CPLString osArrayPath = TileDBDataset::VSI_to_tiledb_uri(pszFilename);
139 :
140 16 : if (vfs.is_dir(osArrayPath))
141 : {
142 0 : vfs.remove_dir(osArrayPath);
143 0 : return CE_None;
144 : }
145 : else
146 16 : return CE_Failure;
147 : }
148 0 : catch (const tiledb::TileDBError &e)
149 : {
150 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
151 0 : return CE_Failure;
152 : }
153 : }
154 :
155 : /************************************************************************/
156 : /* Open() */
157 : /************************************************************************/
158 :
159 251 : GDALDataset *TileDBDataset::Open(GDALOpenInfo *poOpenInfo)
160 :
161 : {
162 : try
163 : {
164 251 : const auto eIdentify = TileDBDataset::Identify(poOpenInfo);
165 251 : if (eIdentify == GDAL_IDENTIFY_FALSE)
166 5 : return nullptr;
167 :
168 246 : if (STARTS_WITH_CI(poOpenInfo->pszFilename, "TILEDB:") &&
169 2 : !STARTS_WITH_CI(poOpenInfo->pszFilename, "TILEDB://"))
170 : {
171 : // subdataset URI so this is a raster
172 2 : return TileDBRasterDataset::Open(poOpenInfo,
173 2 : tiledb::Object::Type::Invalid);
174 : }
175 : else
176 : {
177 244 : if ((poOpenInfo->nOpenFlags & GDAL_OF_MULTIDIM_RASTER) != 0)
178 : {
179 29 : return TileDBDataset::OpenMultiDimensional(poOpenInfo);
180 : }
181 :
182 430 : const char *pszConfig = CSLFetchNameValue(
183 215 : poOpenInfo->papszOpenOptions, "TILEDB_CONFIG");
184 430 : tiledb::Context oCtx;
185 :
186 215 : if (pszConfig != nullptr)
187 : {
188 0 : tiledb::Config cfg(pszConfig);
189 0 : oCtx = tiledb::Context(cfg);
190 : }
191 : else
192 : {
193 215 : tiledb::Config cfg;
194 215 : cfg["sm.enable_signal_handlers"] = "false";
195 215 : oCtx = tiledb::Context(cfg);
196 : }
197 : const std::string osPath =
198 430 : TileDBDataset::VSI_to_tiledb_uri(poOpenInfo->pszFilename);
199 :
200 215 : const auto eType = tiledb::Object::object(oCtx, osPath).type();
201 430 : std::string osDatasetType;
202 215 : if (eType == tiledb::Object::Type::Group)
203 : {
204 240 : tiledb::Group group(oCtx, osPath, TILEDB_READ);
205 120 : tiledb_datatype_t v_type = TILEDB_UINT8;
206 120 : const void *v_r = nullptr;
207 120 : uint32_t v_num = 0;
208 120 : group.get_metadata(DATASET_TYPE_ATTRIBUTE_NAME, &v_type, &v_num,
209 : &v_r);
210 116 : if (v_r && (v_type == TILEDB_UINT8 || v_type == TILEDB_CHAR ||
211 116 : v_type == TILEDB_STRING_ASCII ||
212 236 : v_type == TILEDB_STRING_UTF8))
213 : {
214 : osDatasetType =
215 116 : std::string(static_cast<const char *>(v_r), v_num);
216 : }
217 : }
218 :
219 61 : if ((poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) != 0 &&
220 299 : eType == tiledb::Object::Type::Group &&
221 49 : (osDatasetType.empty() ||
222 23 : osDatasetType == GEOMETRY_DATASET_TYPE))
223 : {
224 3 : return OGRTileDBDataset::Open(poOpenInfo, eType);
225 : }
226 614 : else if ((poOpenInfo->nOpenFlags & GDAL_OF_RASTER) != 0 &&
227 190 : (poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) == 0 &&
228 402 : eType == tiledb::Object::Type::Group &&
229 94 : osDatasetType == GEOMETRY_DATASET_TYPE)
230 : {
231 0 : return nullptr;
232 : }
233 190 : else if ((poOpenInfo->nOpenFlags & GDAL_OF_RASTER) != 0 &&
234 402 : eType == tiledb::Object::Type::Group &&
235 117 : osDatasetType == RASTER_DATASET_TYPE)
236 : {
237 116 : return TileDBRasterDataset::Open(poOpenInfo, eType);
238 : }
239 227 : else if ((poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) != 0 &&
240 35 : (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) == 0 &&
241 131 : eType == tiledb::Object::Type::Group &&
242 0 : osDatasetType == RASTER_DATASET_TYPE)
243 : {
244 0 : return nullptr;
245 : }
246 74 : else if ((poOpenInfo->nOpenFlags & GDAL_OF_RASTER) != 0 &&
247 170 : eType == tiledb::Object::Type::Group &&
248 1 : osDatasetType.empty())
249 : {
250 : // Compatibility with generic arrays
251 : // If this is a group which has only a single 2D array and
252 : // no 3D+ arrays, then return this 2D array.
253 : auto poDSUnique = std::unique_ptr<GDALDataset>(
254 2 : TileDBDataset::OpenMultiDimensional(poOpenInfo));
255 1 : if (poDSUnique)
256 : {
257 1 : auto poRootGroup = poDSUnique->GetRootGroup();
258 1 : if (poRootGroup && poRootGroup->GetGroupNames().empty())
259 : {
260 0 : std::shared_ptr<GDALMDArray> poCandidateArray;
261 4 : for (const auto &osName :
262 9 : poRootGroup->GetMDArrayNames())
263 : {
264 4 : auto poArray = poRootGroup->OpenMDArray(osName);
265 4 : if (poArray && poArray->GetDimensionCount() >= 3)
266 : {
267 0 : poCandidateArray.reset();
268 0 : break;
269 : }
270 8 : else if (poArray &&
271 9 : poArray->GetDimensionCount() == 2 &&
272 1 : poArray->GetDimensions()[0]->GetType() ==
273 8 : GDAL_DIM_TYPE_HORIZONTAL_Y &&
274 1 : poArray->GetDimensions()[1]->GetType() ==
275 : GDAL_DIM_TYPE_HORIZONTAL_X)
276 : {
277 1 : if (!poCandidateArray)
278 : {
279 1 : poCandidateArray = std::move(poArray);
280 : }
281 : else
282 : {
283 0 : poCandidateArray.reset();
284 0 : break;
285 : }
286 : }
287 : }
288 1 : if (poCandidateArray)
289 : {
290 1 : return poCandidateArray->AsClassicDataset(1, 0);
291 : }
292 : }
293 : }
294 0 : return nullptr;
295 : }
296 :
297 136 : tiledb::ArraySchema schema(oCtx, osPath);
298 :
299 41 : if (schema.array_type() == TILEDB_SPARSE)
300 35 : return OGRTileDBDataset::Open(poOpenInfo, eType);
301 : else
302 6 : return TileDBRasterDataset::Open(poOpenInfo, eType);
303 : }
304 : }
305 54 : catch (const tiledb::TileDBError &e)
306 : {
307 54 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
308 54 : return nullptr;
309 : }
310 : }
311 :
312 : /************************************************************************/
313 : /* Create() */
314 : /************************************************************************/
315 :
316 114 : GDALDataset *TileDBDataset::Create(const char *pszFilename, int nXSize,
317 : int nYSize, int nBandsIn, GDALDataType eType,
318 : char **papszOptions)
319 :
320 : {
321 : try
322 : {
323 114 : if (nBandsIn > 0)
324 64 : return TileDBRasterDataset::Create(pszFilename, nXSize, nYSize,
325 64 : nBandsIn, eType, papszOptions);
326 : else
327 50 : return OGRTileDBDataset::Create(pszFilename, papszOptions);
328 : }
329 0 : catch (const tiledb::TileDBError &e)
330 : {
331 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
332 : }
333 :
334 0 : return nullptr;
335 : }
336 :
337 : /************************************************************************/
338 : /* CreateCopy() */
339 : /************************************************************************/
340 :
341 54 : GDALDataset *TileDBDataset::CreateCopy(const char *pszFilename,
342 : GDALDataset *poSrcDS, int bStrict,
343 : char **papszOptions,
344 : GDALProgressFunc pfnProgress,
345 : void *pProgressData)
346 :
347 : {
348 54 : if (poSrcDS->GetRootGroup())
349 : {
350 1 : auto poDrv = GDALDriver::FromHandle(GDALGetDriverByName("TileDB"));
351 1 : if (poDrv)
352 : {
353 1 : return poDrv->DefaultCreateCopy(pszFilename, poSrcDS, bStrict,
354 : papszOptions, pfnProgress,
355 1 : pProgressData);
356 : }
357 : }
358 :
359 : try
360 : {
361 55 : if (poSrcDS->GetRasterCount() > 0 ||
362 2 : poSrcDS->GetMetadata("SUBDATASETS"))
363 : {
364 52 : return TileDBRasterDataset::CreateCopy(pszFilename, poSrcDS,
365 : bStrict, papszOptions,
366 52 : pfnProgress, pProgressData);
367 : }
368 : }
369 0 : catch (const tiledb::TileDBError &e)
370 : {
371 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
372 : }
373 :
374 1 : return nullptr;
375 : }
376 :
377 : /************************************************************************/
378 : /* GDALRegister_TILEDB() */
379 : /************************************************************************/
380 :
381 28 : void GDALRegister_TileDB()
382 :
383 : {
384 28 : if (GDALGetDriverByName(DRIVER_NAME) != nullptr)
385 0 : return;
386 :
387 28 : GDALDriver *poDriver = new GDALDriver();
388 28 : TileDBDriverSetCommonMetadata(poDriver);
389 :
390 28 : poDriver->pfnIdentify = TileDBDataset::Identify;
391 28 : poDriver->pfnOpen = TileDBDataset::Open;
392 28 : poDriver->pfnCreate = TileDBDataset::Create;
393 28 : poDriver->pfnCreateCopy = TileDBDataset::CreateCopy;
394 28 : poDriver->pfnDelete = TileDBDataset::Delete;
395 28 : poDriver->pfnCreateMultiDimensional = TileDBDataset::CreateMultiDimensional;
396 :
397 28 : GetGDALDriverManager()->RegisterDriver(poDriver);
398 : }
|