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: 2025-01-18 12:42:00 Functions: 14 17 82.4 %

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

Generated by: LCOV version 1.14