LCOV - code coverage report
Current view: top level - autotest/cpp - testblockcache.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 226 310 72.9 %
Date: 2024-05-13 13:33:37 Functions: 14 17 82.4 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * $Id$
       3             :  *
       4             :  * Project:  GDAL Core
       5             :  * Purpose:  Test block cache under multi-threading
       6             :  * Author:   Even Rouault, <even dot rouault at spatialys dot com>
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2015, Even Rouault <even dot rouault at spatialys dot com>
      10             :  *
      11             :  * Permission is hereby granted, free of charge, to any person obtaining a
      12             :  * copy of this software and associated documentation files (the "Software"),
      13             :  * to deal in the Software without restriction, including without limitation
      14             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15             :  * and/or sell copies of the Software, and to permit persons to whom the
      16             :  * Software is furnished to do so, subject to the following conditions:
      17             :  *
      18             :  * The above copyright notice and this permission notice shall be included
      19             :  * in all copies or substantial portions of the Software.
      20             :  *
      21             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27             :  * DEALINGS IN THE SOFTWARE.
      28             :  ****************************************************************************/
      29             : 
      30             : #ifndef DEBUG
      31             : #define DEBUG
      32             : #endif
      33             : 
      34             : #include "cpl_multiproc.h"
      35             : #include "gdal_priv.h"
      36             : 
      37             : #include <cstdlib>
      38             : #include <vector>
      39             : 
      40             : #include "gtest_include.h"
      41             : 
      42             : extern int global_argc;
      43             : extern char **global_argv;
      44             : 
      45             : namespace
      46             : {
      47             : 
      48             : CPLLock *psLock = nullptr;
      49             : 
      50           0 : static void Usage()
      51             : {
      52           0 :     printf("Usage: testblockcache [-threads X] [-loops X] [-max_requests X] "
      53             :            "[-strategy random|line|block]\n");
      54           0 :     printf("                      [-migrate] [ filename |\n");
      55           0 :     printf("                       [[-xsize val] [-ysize val] [-bands val] "
      56             :            "[-co key=value]*\n");
      57           0 :     printf("                       [[-memdriver] | [-ondisk]] [-check]] ]\n");
      58           0 :     exit(1);
      59             : }
      60             : 
      61             : int nLoops = 1;
      62             : const char *pszDataset = nullptr;
      63             : int bCheck = FALSE;
      64             : 
      65             : typedef enum
      66             : {
      67             :     STRATEGY_RANDOM,
      68             :     STRATEGY_LINE,
      69             :     STRATEGY_BLOCK,
      70             : } Strategy;
      71             : 
      72             : typedef struct _Request Request;
      73             : 
      74             : struct _Request
      75             : {
      76             :     int nXOff, nYOff, nXWin, nYWin;
      77             :     int nBands;
      78             :     Request *psNext;
      79             : };
      80             : 
      81             : typedef struct _Resource Resource;
      82             : 
      83             : struct _Resource
      84             : {
      85             :     GDALDataset *poDS;
      86             :     void *pBuffer;
      87             :     Resource *psNext;
      88             :     Resource *psPrev;
      89             : };
      90             : 
      91             : typedef struct
      92             : {
      93             :     GDALDataset *poDS;
      94             :     Request *psRequestList;
      95             :     int nBufferSize;
      96             : } ThreadDescription;
      97             : 
      98             : static Request *psGlobalRequestList = nullptr;
      99             : static Resource *psGlobalResourceList = nullptr;
     100             : static Resource *psGlobalResourceLast = nullptr;
     101             : 
     102             : /* according to rand() man page, POSIX.1-2001 proposes the following
     103             :  * implementation */
     104             : /* RAND_MAX assumed to be 32767 */
     105             : #define MYRAND_MAX 32767
     106             : 
     107  5453030000 : static int myrand_r(unsigned long *pseed)
     108             : {
     109  5453030000 :     *pseed = *pseed * 1103515245 + 12345;
     110  5453030000 :     return ((unsigned)((*pseed / 65536UL) % (MYRAND_MAX + 1)));
     111             : }
     112             : 
     113       22400 : static void Check(GByte *pBuffer, int nXSize, int nYSize, int nBands, int nXOff,
     114             :                   int nYOff, int nXWin, int nYWin)
     115             : {
     116      112000 :     for (int iBand = 0; iBand < nBands; iBand++)
     117             :     {
     118    21681600 :         for (int iY = 0; iY < nYWin; iY++)
     119             :         {
     120  5157160000 :             for (int iX = 0; iX < nXWin; iX++)
     121             :             {
     122  5135570000 :                 unsigned long seed = iBand * nXSize * nYSize +
     123  5135570000 :                                      (iY + nYOff) * nXSize + iX + nXOff;
     124  5135570000 :                 GByte expected = (GByte)(myrand_r(&seed) & 0xff);
     125  5250460000 :                 EXPECT_EQ(pBuffer[iBand * nXWin * nYWin + iY * nXWin + iX],
     126             :                           expected);
     127             :             }
     128             :         }
     129             :     }
     130       22400 : }
     131             : 
     132       22400 : static void ReadRaster(GDALDataset *poDS, int nXSize, int nYSize, int nBands,
     133             :                        GByte *pBuffer, int nXOff, int nYOff, int nXWin,
     134             :                        int nYWin)
     135             : {
     136       22400 :     CPL_IGNORE_RET_VAL(poDS->RasterIO(GF_Read, nXOff, nYOff, nXWin, nYWin,
     137             :                                       pBuffer, nXWin, nYWin, GDT_Byte, nBands,
     138             :                                       nullptr, 0, 0, 0
     139             : #ifdef GDAL_COMPILATION
     140             :                                       ,
     141             :                                       nullptr
     142             : #endif
     143             :                                       ));
     144       22400 :     if (bCheck)
     145             :     {
     146       22400 :         Check(pBuffer, nXSize, nYSize, nBands, nXOff, nYOff, nXWin, nYWin);
     147             :     }
     148       22400 : }
     149             : 
     150       22400 : static void AddRequest(Request *&psRequestList, Request *&psRequestLast,
     151             :                        int nXOff, int nYOff, int nXWin, int nYWin, int nBands)
     152             : {
     153       22400 :     Request *psRequest = (Request *)CPLMalloc(sizeof(Request));
     154       22400 :     psRequest->nXOff = nXOff;
     155       22400 :     psRequest->nYOff = nYOff;
     156       22400 :     psRequest->nXWin = nXWin;
     157       22400 :     psRequest->nYWin = nYWin;
     158       22400 :     psRequest->nBands = nBands;
     159       22400 :     if (psRequestLast)
     160       22379 :         psRequestLast->psNext = psRequest;
     161             :     else
     162          21 :         psRequestList = psRequest;
     163       22400 :     psRequestLast = psRequest;
     164       22400 :     psRequest->psNext = nullptr;
     165       22400 : }
     166             : 
     167       22404 : static Request *GetNextRequest(Request *&psRequestList)
     168             : {
     169       22404 :     if (psLock)
     170        1604 :         CPLAcquireLock(psLock);
     171       22404 :     Request *psRet = psRequestList;
     172       22404 :     if (psRequestList)
     173             :     {
     174       22400 :         psRequestList = psRequestList->psNext;
     175       22400 :         psRet->psNext = nullptr;
     176             :     }
     177       22404 :     if (psLock)
     178        1604 :         CPLReleaseLock(psLock);
     179       22404 :     return psRet;
     180             : }
     181             : 
     182        1600 : static Resource *AcquireFirstResource()
     183             : {
     184        1600 :     if (psLock)
     185        1600 :         CPLAcquireLock(psLock);
     186        1600 :     Resource *psRet = psGlobalResourceList;
     187        1600 :     psGlobalResourceList = psGlobalResourceList->psNext;
     188        1600 :     if (psGlobalResourceList)
     189           3 :         psGlobalResourceList->psPrev = nullptr;
     190             :     else
     191        1597 :         psGlobalResourceLast = nullptr;
     192        1600 :     psRet->psNext = nullptr;
     193        1600 :     CPLAssert(psRet->psPrev == nullptr);
     194        1600 :     if (psLock)
     195        1600 :         CPLReleaseLock(psLock);
     196        1600 :     return psRet;
     197             : }
     198             : 
     199        1604 : static void PutResourceAtEnd(Resource *psResource)
     200             : {
     201        1604 :     if (psLock)
     202        1600 :         CPLAcquireLock(psLock);
     203        1604 :     psResource->psPrev = psGlobalResourceLast;
     204        1604 :     psResource->psNext = nullptr;
     205        1604 :     if (psGlobalResourceList == nullptr)
     206        1598 :         psGlobalResourceList = psResource;
     207             :     else
     208           6 :         psGlobalResourceLast->psNext = psResource;
     209        1604 :     psGlobalResourceLast = psResource;
     210        1604 :     if (psLock)
     211        1600 :         CPLReleaseLock(psLock);
     212        1604 : }
     213             : 
     214          20 : static void ThreadFuncDedicatedDataset(void *_psThreadDescription)
     215             : {
     216          20 :     ThreadDescription *psThreadDescription =
     217             :         (ThreadDescription *)_psThreadDescription;
     218          20 :     int nXSize = psThreadDescription->poDS->GetRasterXSize();
     219          20 :     int nYSize = psThreadDescription->poDS->GetRasterYSize();
     220          20 :     void *pBuffer = CPLMalloc(psThreadDescription->nBufferSize);
     221       20820 :     while (psThreadDescription->psRequestList != nullptr)
     222             :     {
     223       20800 :         Request *psRequest = GetNextRequest(psThreadDescription->psRequestList);
     224       20800 :         ReadRaster(psThreadDescription->poDS, nXSize, nYSize, psRequest->nBands,
     225             :                    (GByte *)pBuffer, psRequest->nXOff, psRequest->nYOff,
     226             :                    psRequest->nXWin, psRequest->nYWin);
     227       20800 :         CPLFree(psRequest);
     228             :     }
     229          20 :     CPLFree(pBuffer);
     230          20 : }
     231             : 
     232        1604 : static void ThreadFuncWithMigration(void * /* _unused */)
     233             : {
     234             :     Request *psRequest;
     235        1604 :     while ((psRequest = GetNextRequest(psGlobalRequestList)) != nullptr)
     236             :     {
     237        1600 :         Resource *psResource = AcquireFirstResource();
     238        1600 :         ASSERT_TRUE(psResource != nullptr);
     239        1600 :         int nXSize = psResource->poDS->GetRasterXSize();
     240        1600 :         int nYSize = psResource->poDS->GetRasterYSize();
     241        1600 :         ReadRaster(psResource->poDS, nXSize, nYSize, psRequest->nBands,
     242        1600 :                    (GByte *)psResource->pBuffer, psRequest->nXOff,
     243             :                    psRequest->nYOff, psRequest->nXWin, psRequest->nYWin);
     244        1600 :         CPLFree(psRequest);
     245        1600 :         PutResourceAtEnd(psResource);
     246             :     }
     247             : }
     248             : 
     249          24 : static int CreateRandomStrategyRequests(GDALDataset *poDS, int nMaxRequests,
     250             :                                         Request *&psRequestList,
     251             :                                         Request *&psRequestLast)
     252             : {
     253          24 :     unsigned long seed = 1;
     254          24 :     int nXSize = poDS->GetRasterXSize();
     255          24 :     int nYSize = poDS->GetRasterYSize();
     256          24 :     int nMaxXWin = MIN(1000, nXSize / 10 + 1);
     257          24 :     int nMaxYWin = MIN(1000, nYSize / 10 + 1);
     258          24 :     int nQueriedBands = MIN(4, poDS->GetRasterCount());
     259          24 :     int nAverageIterationsToReadWholeFile =
     260          24 :         ((nXSize + nMaxXWin / 2 - 1) / (nMaxXWin / 2)) *
     261          24 :         ((nYSize + nMaxYWin / 2 - 1) / (nMaxYWin / 2));
     262          24 :     int nLocalLoops = nLoops * nAverageIterationsToReadWholeFile;
     263       22424 :     for (int iLoop = 0; iLoop < nLocalLoops; iLoop++)
     264             :     {
     265       22400 :         if (nMaxRequests > 0 && iLoop == nMaxRequests)
     266           0 :             break;
     267       22400 :         int nXOff = (int)((GIntBig)myrand_r(&seed) * (nXSize - 1) / MYRAND_MAX);
     268       22400 :         int nYOff = (int)((GIntBig)myrand_r(&seed) * (nYSize - 1) / MYRAND_MAX);
     269       22400 :         int nXWin = 1 + (int)((GIntBig)myrand_r(&seed) * nMaxXWin / MYRAND_MAX);
     270       22400 :         int nYWin = 1 + (int)((GIntBig)myrand_r(&seed) * nMaxYWin / MYRAND_MAX);
     271       22400 :         if (nXOff + nXWin > nXSize)
     272        1200 :             nXWin = nXSize - nXOff;
     273       22400 :         if (nYOff + nYWin > nYSize)
     274        1184 :             nYWin = nYSize - nYOff;
     275       22400 :         AddRequest(psRequestList, psRequestLast, nXOff, nYOff, nXWin, nYWin,
     276             :                    nQueriedBands);
     277             :     }
     278          24 :     return nQueriedBands * nMaxXWin * nMaxYWin;
     279             : }
     280             : 
     281           0 : static int CreateLineStrategyRequests(GDALDataset *poDS, int nMaxRequests,
     282             :                                       Request *&psRequestList,
     283             :                                       Request *&psRequestLast)
     284             : {
     285           0 :     int nXSize = poDS->GetRasterXSize();
     286           0 :     int nYSize = poDS->GetRasterYSize();
     287           0 :     int nQueriedBands = MIN(4, poDS->GetRasterCount());
     288           0 :     int bStop = FALSE;
     289           0 :     int nRequests = 0;
     290           0 :     for (int iLoop = 0; !bStop && iLoop < nLoops; iLoop++)
     291             :     {
     292           0 :         for (int nYOff = 0; nYOff < nYSize; nYOff++)
     293             :         {
     294           0 :             if (nMaxRequests > 0 && nRequests == nMaxRequests)
     295             :             {
     296           0 :                 bStop = TRUE;
     297           0 :                 break;
     298             :             }
     299           0 :             AddRequest(psRequestList, psRequestLast, 0, nYOff, nXSize, 1,
     300             :                        nQueriedBands);
     301           0 :             nRequests++;
     302             :         }
     303             :     }
     304           0 :     return nQueriedBands * nXSize;
     305             : }
     306             : 
     307           0 : static int CreateBlockStrategyRequests(GDALDataset *poDS, int nMaxRequests,
     308             :                                        Request *&psRequestList,
     309             :                                        Request *&psRequestLast)
     310             : {
     311           0 :     int nXSize = poDS->GetRasterXSize();
     312           0 :     int nYSize = poDS->GetRasterYSize();
     313           0 :     int nMaxXWin = MIN(1000, nXSize / 10 + 1);
     314           0 :     int nMaxYWin = MIN(1000, nYSize / 10 + 1);
     315           0 :     int nQueriedBands = MIN(4, poDS->GetRasterCount());
     316           0 :     int bStop = FALSE;
     317           0 :     int nRequests = 0;
     318           0 :     for (int iLoop = 0; !bStop && iLoop < nLoops; iLoop++)
     319             :     {
     320           0 :         for (int nYOff = 0; !bStop && nYOff < nYSize; nYOff += nMaxYWin)
     321             :         {
     322           0 :             int nReqYSize =
     323           0 :                 (nYOff + nMaxYWin > nYSize) ? nYSize - nYOff : nMaxYWin;
     324           0 :             for (int nXOff = 0; nXOff < nXSize; nXOff += nMaxXWin)
     325             :             {
     326           0 :                 if (nMaxRequests > 0 && nRequests == nMaxRequests)
     327             :                 {
     328           0 :                     bStop = TRUE;
     329           0 :                     break;
     330             :                 }
     331           0 :                 int nReqXSize =
     332           0 :                     (nXOff + nMaxXWin > nXSize) ? nXSize - nXOff : nMaxXWin;
     333           0 :                 AddRequest(psRequestList, psRequestLast, nXOff, nYOff,
     334             :                            nReqXSize, nReqYSize, nQueriedBands);
     335           0 :                 nRequests++;
     336             :             }
     337             :         }
     338             :     }
     339           0 :     return nQueriedBands * nMaxXWin * nMaxYWin;
     340             : }
     341             : 
     342          24 : TEST(testblockcache, test)
     343             : {
     344             :     int i;
     345           6 :     int nThreads = CPLGetNumCPUs();
     346          12 :     std::vector<CPLJoinableThread *> apsThreads;
     347           6 :     Strategy eStrategy = STRATEGY_RANDOM;
     348           6 :     int bNewDatasetOption = FALSE;
     349           6 :     int nXSize = 5000;
     350           6 :     int nYSize = 5000;
     351           6 :     int nBands = 4;
     352           6 :     char **papszOptions = nullptr;
     353           6 :     int bOnDisk = FALSE;
     354          12 :     std::vector<ThreadDescription> asThreadDescription;
     355           6 :     int bMemDriver = FALSE;
     356           6 :     GDALDataset *poMEMDS = nullptr;
     357           6 :     int bMigrate = FALSE;
     358           6 :     int nMaxRequests = -1;
     359             : 
     360           6 :     GDALAllRegister();
     361             : 
     362           6 :     int argc = global_argc;
     363           6 :     char **argv = global_argv;
     364          23 :     for (i = 1; i < argc; i++)
     365             :     {
     366          17 :         if (EQUAL(argv[i], "-threads") && i + 1 < argc)
     367             :         {
     368           0 :             i++;
     369           0 :             nThreads = atoi(argv[i]);
     370             :         }
     371          17 :         else if (EQUAL(argv[i], "-loops") && i + 1 < argc)
     372             :         {
     373           4 :             i++;
     374           4 :             nLoops = atoi(argv[i]);
     375           4 :             if (nLoops <= 0)
     376           0 :                 nLoops = INT_MAX;
     377             :         }
     378          13 :         else if (EQUAL(argv[i], "-max_requests") && i + 1 < argc)
     379             :         {
     380           0 :             i++;
     381           0 :             nMaxRequests = atoi(argv[i]);
     382             :         }
     383          13 :         else if (EQUAL(argv[i], "-strategy") && i + 1 < argc)
     384             :         {
     385           0 :             i++;
     386           0 :             if (EQUAL(argv[i], "random"))
     387           0 :                 eStrategy = STRATEGY_RANDOM;
     388           0 :             else if (EQUAL(argv[i], "line"))
     389           0 :                 eStrategy = STRATEGY_LINE;
     390           0 :             else if (EQUAL(argv[i], "block"))
     391           0 :                 eStrategy = STRATEGY_BLOCK;
     392             :             else
     393           0 :                 Usage();
     394             :         }
     395          13 :         else if (EQUAL(argv[i], "-xsize") && i + 1 < argc)
     396             :         {
     397           0 :             i++;
     398           0 :             nXSize = atoi(argv[i]);
     399           0 :             bNewDatasetOption = TRUE;
     400             :         }
     401          13 :         else if (EQUAL(argv[i], "-ysize") && i + 1 < argc)
     402             :         {
     403           0 :             i++;
     404           0 :             nYSize = atoi(argv[i]);
     405           0 :             bNewDatasetOption = TRUE;
     406             :         }
     407          13 :         else if (EQUAL(argv[i], "-bands") && i + 1 < argc)
     408             :         {
     409           0 :             i++;
     410           0 :             nBands = atoi(argv[i]);
     411           0 :             bNewDatasetOption = TRUE;
     412             :         }
     413          13 :         else if (EQUAL(argv[i], "-co") && i + 1 < argc)
     414             :         {
     415           5 :             i++;
     416           5 :             papszOptions = CSLAddString(papszOptions, argv[i]);
     417           5 :             bNewDatasetOption = TRUE;
     418             :         }
     419           8 :         else if (EQUAL(argv[i], "-ondisk"))
     420             :         {
     421           0 :             bOnDisk = TRUE;
     422           0 :             bNewDatasetOption = TRUE;
     423             :         }
     424           8 :         else if (EQUAL(argv[i], "-check"))
     425             :         {
     426           6 :             bCheck = TRUE;
     427           6 :             bNewDatasetOption = TRUE;
     428             :         }
     429           2 :         else if (EQUAL(argv[i], "-memdriver"))
     430             :         {
     431           1 :             bMemDriver = TRUE;
     432           1 :             bNewDatasetOption = TRUE;
     433             :         }
     434           1 :         else if (EQUAL(argv[i], "-migrate"))
     435           1 :             bMigrate = TRUE;
     436           0 :         else if (argv[i][0] == '-')
     437           0 :             Usage();
     438           0 :         else if (pszDataset == nullptr)
     439           0 :             pszDataset = argv[i];
     440             :         else
     441             :         {
     442           0 :             Usage();
     443             :         }
     444             :     }
     445             : 
     446           6 :     if (pszDataset != nullptr && bNewDatasetOption)
     447           0 :         Usage();
     448             : 
     449           6 :     CPLDebug("TEST", "Using %d threads", nThreads);
     450             : 
     451           6 :     int bCreatedDataset = FALSE;
     452           6 :     if (pszDataset == nullptr)
     453             :     {
     454           6 :         bCreatedDataset = TRUE;
     455           6 :         if (bOnDisk)
     456           0 :             pszDataset = "/tmp/tmp.tif";
     457             :         else
     458           6 :             pszDataset = "/vsimem/tmp.tif";
     459             :         GDALDataset *poDS =
     460           6 :             ((GDALDriver *)GDALGetDriverByName((bMemDriver) ? "MEM" : "GTiff"))
     461           6 :                 ->Create(pszDataset, nXSize, nYSize, nBands, GDT_Byte,
     462             :                          papszOptions);
     463           6 :         if (bCheck)
     464             :         {
     465             :             GByte *pabyLine =
     466           6 :                 (GByte *)VSIMalloc(static_cast<size_t>(nBands) * nXSize);
     467       30006 :             for (int iY = 0; iY < nYSize; iY++)
     468             :             {
     469   150030000 :                 for (int iX = 0; iX < nXSize; iX++)
     470             :                 {
     471   750000000 :                     for (int iBand = 0; iBand < nBands; iBand++)
     472             :                     {
     473   600000000 :                         unsigned long seed =
     474   600000000 :                             iBand * nXSize * nYSize + iY * nXSize + iX;
     475   600000000 :                         pabyLine[iBand * nXSize + iX] =
     476   600000000 :                             (GByte)(myrand_r(&seed) & 0xff);
     477             :                     }
     478             :                 }
     479       30000 :                 CPL_IGNORE_RET_VAL(poDS->RasterIO(GF_Write, 0, iY, nXSize, 1,
     480             :                                                   pabyLine, nXSize, 1, GDT_Byte,
     481             :                                                   nBands, nullptr, 0, 0, 0
     482             : #ifdef GDAL_COMPILATION
     483             :                                                   ,
     484             :                                                   nullptr
     485             : #endif
     486             :                                                   ));
     487             :             }
     488           6 :             VSIFree(pabyLine);
     489             :         }
     490           6 :         if (bMemDriver)
     491           1 :             poMEMDS = poDS;
     492             :         else
     493           5 :             GDALClose(poDS);
     494             :     }
     495             :     else
     496             :     {
     497           0 :         bCheck = FALSE;
     498             :     }
     499           6 :     CSLDestroy(papszOptions);
     500           6 :     papszOptions = nullptr;
     501             : 
     502           6 :     Request *psGlobalRequestLast = nullptr;
     503             : 
     504          30 :     for (i = 0; i < nThreads; i++)
     505             :     {
     506             :         GDALDataset *poDS;
     507             :         // Since GDAL 2.0, the MEM driver is thread-safe, i.e. does not use the
     508             :         // block cache, but only for operations not involving resampling, which
     509             :         // is the case here
     510          24 :         if (poMEMDS)
     511           4 :             poDS = poMEMDS;
     512             :         else
     513             :         {
     514          20 :             poDS = (GDALDataset *)GDALOpen(pszDataset, GA_ReadOnly);
     515          20 :             if (poDS == nullptr)
     516           0 :                 exit(1);
     517             :         }
     518          24 :         if (bMigrate)
     519             :         {
     520           4 :             Resource *psResource = (Resource *)CPLMalloc(sizeof(Resource));
     521           4 :             psResource->poDS = poDS;
     522             :             int nBufferSize;
     523           4 :             if (eStrategy == STRATEGY_RANDOM)
     524           4 :                 nBufferSize = CreateRandomStrategyRequests(poDS, nMaxRequests,
     525             :                                                            psGlobalRequestList,
     526             :                                                            psGlobalRequestLast);
     527           0 :             else if (eStrategy == STRATEGY_LINE)
     528           0 :                 nBufferSize = CreateLineStrategyRequests(poDS, nMaxRequests,
     529             :                                                          psGlobalRequestList,
     530             :                                                          psGlobalRequestLast);
     531             :             else
     532           0 :                 nBufferSize = CreateBlockStrategyRequests(poDS, nMaxRequests,
     533             :                                                           psGlobalRequestList,
     534             :                                                           psGlobalRequestLast);
     535           4 :             psResource->pBuffer = CPLMalloc(nBufferSize);
     536           4 :             PutResourceAtEnd(psResource);
     537             :         }
     538             :         else
     539             :         {
     540             :             ThreadDescription sThreadDescription;
     541          20 :             sThreadDescription.poDS = poDS;
     542          20 :             sThreadDescription.psRequestList = nullptr;
     543          20 :             Request *psRequestLast = nullptr;
     544          20 :             if (eStrategy == STRATEGY_RANDOM)
     545          20 :                 sThreadDescription.nBufferSize = CreateRandomStrategyRequests(
     546             :                     poDS, nMaxRequests, sThreadDescription.psRequestList,
     547             :                     psRequestLast);
     548           0 :             else if (eStrategy == STRATEGY_LINE)
     549           0 :                 sThreadDescription.nBufferSize = CreateLineStrategyRequests(
     550             :                     poDS, nMaxRequests, sThreadDescription.psRequestList,
     551             :                     psRequestLast);
     552             :             else
     553           0 :                 sThreadDescription.nBufferSize = CreateBlockStrategyRequests(
     554             :                     poDS, nMaxRequests, sThreadDescription.psRequestList,
     555             :                     psRequestLast);
     556          20 :             asThreadDescription.push_back(sThreadDescription);
     557             :         }
     558             :     }
     559             : 
     560           6 :     if (bCreatedDataset && poMEMDS == nullptr && bOnDisk)
     561             :     {
     562           0 :         CPLPushErrorHandler(CPLQuietErrorHandler);
     563           0 :         VSIUnlink(pszDataset);
     564           0 :         CPLPopErrorHandler();
     565             :     }
     566             : 
     567           6 :     if (bMigrate)
     568             :     {
     569           1 :         psLock = CPLCreateLock(LOCK_SPIN);
     570             :     }
     571             : 
     572          30 :     for (i = 0; i < nThreads; i++)
     573             :     {
     574             :         CPLJoinableThread *pThread;
     575          24 :         if (bMigrate)
     576           4 :             pThread = CPLCreateJoinableThread(ThreadFuncWithMigration, nullptr);
     577             :         else
     578          20 :             pThread = CPLCreateJoinableThread(ThreadFuncDedicatedDataset,
     579          20 :                                               &(asThreadDescription[i]));
     580          24 :         apsThreads.push_back(pThread);
     581             :     }
     582          30 :     for (i = 0; i < nThreads; i++)
     583             :     {
     584          24 :         CPLJoinThread(apsThreads[i]);
     585          24 :         if (!bMigrate && poMEMDS == nullptr)
     586          16 :             GDALClose(asThreadDescription[i].poDS);
     587             :     }
     588          10 :     while (psGlobalResourceList != nullptr)
     589             :     {
     590           4 :         CPLFree(psGlobalResourceList->pBuffer);
     591           4 :         if (poMEMDS == nullptr)
     592           4 :             GDALClose(psGlobalResourceList->poDS);
     593           4 :         Resource *psNext = psGlobalResourceList->psNext;
     594           4 :         CPLFree(psGlobalResourceList);
     595           4 :         psGlobalResourceList = psNext;
     596             :     }
     597             : 
     598           6 :     if (psLock)
     599             :     {
     600           1 :         CPLDestroyLock(psLock);
     601             :     }
     602             : 
     603           6 :     if (bCreatedDataset && poMEMDS == nullptr)
     604             :     {
     605           5 :         CPLPushErrorHandler(CPLQuietErrorHandler);
     606           5 :         VSIUnlink(pszDataset);
     607           5 :         CPLPopErrorHandler();
     608             :     }
     609           6 :     if (poMEMDS)
     610           1 :         GDALClose(poMEMDS);
     611             : 
     612           6 :     EXPECT_EQ(GDALGetCacheUsed64(), 0);
     613             : 
     614           6 :     GDALDestroyDriverManager();
     615           6 : }
     616             : 
     617             : }  // namespace

Generated by: LCOV version 1.14