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

Generated by: LCOV version 1.14