LCOV - code coverage report
Current view: top level - frmts/tiledb - tiledbcommon.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 124 168 73.8 %
Date: 2024-05-14 13:00:50 Functions: 8 8 100.0 %

          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             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : #include "tiledbheaders.h"
      30             : #include "tiledbdrivercore.h"
      31             : 
      32             : /************************************************************************/
      33             : /*                      VSI_to_tiledb_uri()                             */
      34             : /************************************************************************/
      35             : 
      36        1365 : CPLString TileDBDataset::VSI_to_tiledb_uri(const char *pszUri)
      37             : {
      38        1365 :     CPLString osUri;
      39             : 
      40        1365 :     if (STARTS_WITH_CI(pszUri, "/VSIS3/"))
      41           0 :         osUri.Printf("s3://%s", pszUri + 7);
      42        1365 :     else if (STARTS_WITH_CI(pszUri, "/VSIGS/"))
      43           0 :         osUri.Printf("gcs://%s", pszUri + 7);
      44             :     else
      45             :     {
      46        1365 :         osUri = pszUri;
      47             :         // tiledb (at least at 2.4.2 on Conda) wrongly interprets relative
      48             :         // directories on Windows as absolute ones.
      49        1365 :         if (CPLIsFilenameRelative(pszUri))
      50             :         {
      51         982 :             char *pszCurDir = CPLGetCurrentDir();
      52         982 :             if (pszCurDir)
      53         982 :                 osUri = CPLFormFilename(pszCurDir, pszUri, nullptr);
      54         982 :             CPLFree(pszCurDir);
      55             :         }
      56             :     }
      57             : 
      58        1365 :     return osUri;
      59             : }
      60             : 
      61             : /************************************************************************/
      62             : /*                           AddFilter()                                */
      63             : /************************************************************************/
      64             : 
      65           2 : CPLErr TileDBDataset::AddFilter(tiledb::Context &ctx,
      66             :                                 tiledb::FilterList &filterList,
      67             :                                 const char *pszFilterName, const int level)
      68             : 
      69             : {
      70             :     try
      71             :     {
      72           2 :         if (pszFilterName == nullptr)
      73             :             filterList.add_filter(
      74           0 :                 tiledb::Filter(ctx, TILEDB_FILTER_NONE)
      75           0 :                     .set_option(TILEDB_COMPRESSION_LEVEL, level));
      76           2 :         else if EQUAL (pszFilterName, "GZIP")
      77             :             filterList.add_filter(
      78           0 :                 tiledb::Filter(ctx, TILEDB_FILTER_GZIP)
      79           0 :                     .set_option(TILEDB_COMPRESSION_LEVEL, level));
      80           2 :         else if EQUAL (pszFilterName, "ZSTD")
      81             :             filterList.add_filter(
      82           4 :                 tiledb::Filter(ctx, TILEDB_FILTER_ZSTD)
      83           2 :                     .set_option(TILEDB_COMPRESSION_LEVEL, level));
      84           0 :         else if EQUAL (pszFilterName, "LZ4")
      85             :             filterList.add_filter(
      86           0 :                 tiledb::Filter(ctx, TILEDB_FILTER_LZ4)
      87           0 :                     .set_option(TILEDB_COMPRESSION_LEVEL, level));
      88           0 :         else if EQUAL (pszFilterName, "RLE")
      89             :             filterList.add_filter(
      90           0 :                 tiledb::Filter(ctx, TILEDB_FILTER_RLE)
      91           0 :                     .set_option(TILEDB_COMPRESSION_LEVEL, level));
      92           0 :         else if EQUAL (pszFilterName, "BZIP2")
      93             :             filterList.add_filter(
      94           0 :                 tiledb::Filter(ctx, TILEDB_FILTER_BZIP2)
      95           0 :                     .set_option(TILEDB_COMPRESSION_LEVEL, level));
      96           0 :         else if EQUAL (pszFilterName, "DOUBLE-DELTA")
      97             :             filterList.add_filter(
      98           0 :                 tiledb::Filter(ctx, TILEDB_FILTER_DOUBLE_DELTA));
      99           0 :         else if EQUAL (pszFilterName, "POSITIVE-DELTA")
     100             :             filterList.add_filter(
     101           0 :                 tiledb::Filter(ctx, TILEDB_FILTER_POSITIVE_DELTA));
     102             :         else
     103           0 :             return CE_Failure;
     104             : 
     105           2 :         return CE_None;
     106             :     }
     107           0 :     catch (const tiledb::TileDBError &e)
     108             :     {
     109           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
     110           0 :         return CE_Failure;
     111             :     }
     112             : }
     113             : 
     114             : /************************************************************************/
     115             : /*                              Identify()                              */
     116             : /************************************************************************/
     117             : 
     118       34518 : int TileDBDataset::Identify(GDALOpenInfo *poOpenInfo)
     119             : 
     120             : {
     121       34518 :     if (STARTS_WITH_CI(poOpenInfo->pszFilename, "TILEDB:"))
     122             :     {
     123           4 :         return TRUE;
     124             :     }
     125             : 
     126             :     try
     127             :     {
     128             :         const char *pszConfig =
     129       34514 :             CSLFetchNameValue(poOpenInfo->papszOpenOptions, "TILEDB_CONFIG");
     130             : 
     131       34510 :         if (pszConfig != nullptr)
     132             :         {
     133           0 :             return TRUE;
     134             :         }
     135             : 
     136       34510 :         const bool bIsS3OrGS =
     137       69033 :             STARTS_WITH_CI(poOpenInfo->pszFilename, "/VSIS3/") ||
     138       34523 :             STARTS_WITH_CI(poOpenInfo->pszFilename, "/VSIGS/");
     139             :         // If this is a /vsi virtual file systems, bail out, except if it is S3 or GS.
     140       34510 :         if (!bIsS3OrGS && STARTS_WITH(poOpenInfo->pszFilename, "/vsi"))
     141             :         {
     142       14265 :             return false;
     143             :         }
     144             : 
     145       20248 :         if (poOpenInfo->bIsDirectory ||
     146           3 :             (bIsS3OrGS &&
     147           3 :              !EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "tif")))
     148             :         {
     149         826 :             tiledb::Context ctx;
     150             :             CPLString osArrayPath =
     151         826 :                 TileDBDataset::VSI_to_tiledb_uri(poOpenInfo->pszFilename);
     152         826 :             const auto eType = tiledb::Object::object(ctx, osArrayPath).type();
     153         826 :             if ((poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) != 0)
     154             :             {
     155         502 :                 if (eType == tiledb::Object::Type::Array ||
     156             :                     eType == tiledb::Object::Type::Group)
     157         119 :                     return true;
     158             :             }
     159             : 
     160         707 :             if ((poOpenInfo->nOpenFlags & GDAL_OF_MULTIDIM_RASTER) != 0)
     161             :             {
     162         121 :                 if (eType == tiledb::Object::Type::Array ||
     163             :                     eType == tiledb::Object::Type::Group)
     164          52 :                     return true;
     165             :             }
     166         655 :             if ((poOpenInfo->nOpenFlags & GDAL_OF_RASTER) != 0)
     167             :             {
     168         216 :                 if (eType == tiledb::Object::Type::Group)
     169           2 :                     return GDAL_IDENTIFY_UNKNOWN;
     170         214 :                 return eType == tiledb::Object::Type::Array;
     171             :             }
     172             :         }
     173             : 
     174       19858 :         return FALSE;
     175             :     }
     176           0 :     catch (...)
     177             :     {
     178           0 :         return FALSE;
     179             :     }
     180             : }
     181             : 
     182             : /************************************************************************/
     183             : /*                              Delete()                                */
     184             : /************************************************************************/
     185             : 
     186          48 : CPLErr TileDBDataset::Delete(const char *pszFilename)
     187             : 
     188             : {
     189             :     try
     190             :     {
     191          96 :         tiledb::Context ctx;
     192          96 :         tiledb::VFS vfs(ctx);
     193          96 :         CPLString osArrayPath = TileDBDataset::VSI_to_tiledb_uri(pszFilename);
     194             : 
     195          48 :         if (vfs.is_dir(osArrayPath))
     196             :         {
     197          32 :             vfs.remove_dir(osArrayPath);
     198          32 :             return CE_None;
     199             :         }
     200             :         else
     201          16 :             return CE_Failure;
     202             :     }
     203           0 :     catch (const tiledb::TileDBError &e)
     204             :     {
     205           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
     206           0 :         return CE_Failure;
     207             :     }
     208             : }
     209             : 
     210             : /************************************************************************/
     211             : /*                                Open()                                */
     212             : /************************************************************************/
     213             : 
     214         153 : GDALDataset *TileDBDataset::Open(GDALOpenInfo *poOpenInfo)
     215             : 
     216             : {
     217             :     try
     218             :     {
     219         153 :         const auto eIdentify = TileDBDataset::Identify(poOpenInfo);
     220         153 :         if (eIdentify == GDAL_IDENTIFY_FALSE)
     221           6 :             return nullptr;
     222             : 
     223         147 :         if (STARTS_WITH_CI(poOpenInfo->pszFilename, "TILEDB:") &&
     224           2 :             !STARTS_WITH_CI(poOpenInfo->pszFilename, "TILEDB://"))
     225             :         {
     226             :             // subdataset URI so this is a raster
     227           2 :             return TileDBRasterDataset::Open(poOpenInfo);
     228             :         }
     229             :         else
     230             :         {
     231         145 :             if ((poOpenInfo->nOpenFlags & GDAL_OF_MULTIDIM_RASTER) != 0)
     232             :             {
     233          26 :                 return TileDBDataset::OpenMultiDimensional(poOpenInfo);
     234             :             }
     235             : 
     236         238 :             const char *pszConfig = CSLFetchNameValue(
     237         119 :                 poOpenInfo->papszOpenOptions, "TILEDB_CONFIG");
     238         238 :             tiledb::Context oCtx;
     239             : 
     240         119 :             if (pszConfig != nullptr)
     241             :             {
     242           0 :                 tiledb::Config cfg(pszConfig);
     243           0 :                 oCtx = tiledb::Context(cfg);
     244             :             }
     245             :             else
     246             :             {
     247         119 :                 tiledb::Config cfg;
     248         119 :                 cfg["sm.enable_signal_handlers"] = "false";
     249         119 :                 oCtx = tiledb::Context(cfg);
     250             :             }
     251             :             const std::string osPath =
     252         238 :                 TileDBDataset::VSI_to_tiledb_uri(poOpenInfo->pszFilename);
     253             : 
     254         119 :             const auto eType = tiledb::Object::object(oCtx, osPath).type();
     255         119 :             if ((poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) != 0 &&
     256             :                 eType == tiledb::Object::Type::Group)
     257             :             {
     258           3 :                 return OGRTileDBDataset::Open(poOpenInfo, eType);
     259             :             }
     260         116 :             else if ((poOpenInfo->nOpenFlags & GDAL_OF_RASTER) != 0 &&
     261             :                      eType == tiledb::Object::Type::Group)
     262             :             {
     263             :                 // If this is a group which has only a single 2D array and
     264             :                 // no 3D+ arrays, then return this 2D array.
     265             :                 auto poDSUnique = std::unique_ptr<GDALDataset>(
     266           2 :                     TileDBDataset::OpenMultiDimensional(poOpenInfo));
     267           1 :                 if (poDSUnique)
     268             :                 {
     269           1 :                     auto poRootGroup = poDSUnique->GetRootGroup();
     270           1 :                     if (poRootGroup && poRootGroup->GetGroupNames().empty())
     271             :                     {
     272           0 :                         std::shared_ptr<GDALMDArray> poCandidateArray;
     273           4 :                         for (const auto &osName :
     274           9 :                              poRootGroup->GetMDArrayNames())
     275             :                         {
     276           4 :                             auto poArray = poRootGroup->OpenMDArray(osName);
     277           4 :                             if (poArray && poArray->GetDimensionCount() >= 3)
     278             :                             {
     279           0 :                                 poCandidateArray.reset();
     280           0 :                                 break;
     281             :                             }
     282           8 :                             else if (poArray &&
     283           9 :                                      poArray->GetDimensionCount() == 2 &&
     284           1 :                                      poArray->GetDimensions()[0]->GetType() ==
     285           8 :                                          GDAL_DIM_TYPE_HORIZONTAL_Y &&
     286           1 :                                      poArray->GetDimensions()[1]->GetType() ==
     287             :                                          GDAL_DIM_TYPE_HORIZONTAL_X)
     288             :                             {
     289           1 :                                 if (!poCandidateArray)
     290             :                                 {
     291           1 :                                     poCandidateArray = std::move(poArray);
     292             :                                 }
     293             :                                 else
     294             :                                 {
     295           0 :                                     poCandidateArray.reset();
     296           0 :                                     break;
     297             :                                 }
     298             :                             }
     299             :                         }
     300           1 :                         if (poCandidateArray)
     301             :                         {
     302           1 :                             return poCandidateArray->AsClassicDataset(1, 0);
     303             :                         }
     304             :                     }
     305             :                 }
     306           0 :                 return nullptr;
     307             :             }
     308             : 
     309         230 :             tiledb::ArraySchema schema(oCtx, osPath);
     310             : 
     311         115 :             if (schema.array_type() == TILEDB_SPARSE)
     312          35 :                 return OGRTileDBDataset::Open(poOpenInfo, eType);
     313             :             else
     314          80 :                 return TileDBRasterDataset::Open(poOpenInfo);
     315             :         }
     316             :     }
     317           0 :     catch (const tiledb::TileDBError &e)
     318             :     {
     319           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
     320           0 :         return nullptr;
     321             :     }
     322             : }
     323             : 
     324             : /************************************************************************/
     325             : /*                              Create()                                */
     326             : /************************************************************************/
     327             : 
     328          85 : GDALDataset *TileDBDataset::Create(const char *pszFilename, int nXSize,
     329             :                                    int nYSize, int nBandsIn, GDALDataType eType,
     330             :                                    char **papszOptions)
     331             : 
     332             : {
     333             :     try
     334             :     {
     335          85 :         if (nBandsIn > 0)
     336          35 :             return TileDBRasterDataset::Create(pszFilename, nXSize, nYSize,
     337          35 :                                                nBandsIn, eType, papszOptions);
     338             :         else
     339          50 :             return OGRTileDBDataset::Create(pszFilename, papszOptions);
     340             :     }
     341           0 :     catch (const tiledb::TileDBError &e)
     342             :     {
     343           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
     344             :     }
     345             : 
     346           0 :     return nullptr;
     347             : }
     348             : 
     349             : /************************************************************************/
     350             : /*                              CreateCopy()                            */
     351             : /************************************************************************/
     352             : 
     353          60 : GDALDataset *TileDBDataset::CreateCopy(const char *pszFilename,
     354             :                                        GDALDataset *poSrcDS, int bStrict,
     355             :                                        char **papszOptions,
     356             :                                        GDALProgressFunc pfnProgress,
     357             :                                        void *pProgressData)
     358             : 
     359             : {
     360          60 :     if (poSrcDS->GetRootGroup())
     361             :     {
     362           1 :         auto poDrv = GDALDriver::FromHandle(GDALGetDriverByName("TileDB"));
     363           1 :         if (poDrv)
     364             :         {
     365           1 :             return poDrv->DefaultCreateCopy(pszFilename, poSrcDS, bStrict,
     366             :                                             papszOptions, pfnProgress,
     367           1 :                                             pProgressData);
     368             :         }
     369             :     }
     370             : 
     371             :     try
     372             :     {
     373          61 :         if (poSrcDS->GetRasterCount() > 0 ||
     374           2 :             poSrcDS->GetMetadata("SUBDATASETS"))
     375             :         {
     376          58 :             return TileDBRasterDataset::CreateCopy(pszFilename, poSrcDS,
     377             :                                                    bStrict, papszOptions,
     378          45 :                                                    pfnProgress, pProgressData);
     379             :         }
     380             :     }
     381          26 :     catch (const tiledb::TileDBError &e)
     382             :     {
     383          13 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
     384             :     }
     385             : 
     386          14 :     return nullptr;
     387             : }
     388             : 
     389             : /************************************************************************/
     390             : /*                         GDALRegister_TILEDB()                        */
     391             : /************************************************************************/
     392             : 
     393          15 : void GDALRegister_TileDB()
     394             : 
     395             : {
     396          15 :     if (GDALGetDriverByName(DRIVER_NAME) != nullptr)
     397           0 :         return;
     398             : 
     399          15 :     GDALDriver *poDriver = new GDALDriver();
     400          15 :     TileDBDriverSetCommonMetadata(poDriver);
     401             : 
     402          15 :     poDriver->pfnIdentify = TileDBDataset::Identify;
     403          15 :     poDriver->pfnOpen = TileDBDataset::Open;
     404          15 :     poDriver->pfnCreate = TileDBDataset::Create;
     405          15 :     poDriver->pfnCreateCopy = TileDBDataset::CreateCopy;
     406          15 :     poDriver->pfnDelete = TileDBDataset::Delete;
     407          15 :     poDriver->pfnCreateMultiDimensional = TileDBDataset::CreateMultiDimensional;
     408             : 
     409          15 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     410             : }

Generated by: LCOV version 1.14