LCOV - code coverage report
Current view: top level - frmts/tiledb - tiledbcommon.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 132 179 73.7 %
Date: 2024-11-21 22:18:42 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             :  * 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             : }

Generated by: LCOV version 1.14