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