GDALDataset* GDALProxyPoolDataset::RefUnderlyingDataset() { /* We pretend that the current thread is responsiblePID, that is */ /* to say the thread that created that GDALProxyPoolDataset object. */ /* This is for the case when a GDALProxyPoolDataset is created by a */ /* thread and used by other threads. These other threads, when doing actual */ /* IO, will come there and potentially open the underlying dataset. */ /* By doing this, they can indirectly call GDALOpenShared() on .aux file */ /* for example. So this call to GDALOpenShared() must occur as if it */ /* was done by the creating thread, otherwise it will not be correctly closed afterwards... */ /* To make a long story short : this is necessary when warping with ChunkAndWarpMulti */ /* a VRT of GeoTIFFs that have associated .aux files */ GIntBig curResponsiblePID = GDALGetResponsiblePIDForCurrentThread(); GDALSetResponsiblePIDForCurrentThread(responsiblePID); cacheEntry = GDALDatasetPool::RefDataset(GetDescription(), eAccess); GDALSetResponsiblePIDForCurrentThread(curResponsiblePID); if (cacheEntry != NULL) { if (cacheEntry->poDS != NULL) return cacheEntry->poDS; else GDALDatasetPool::UnrefDataset(cacheEntry); } return NULL; }
void GDALDatasetPool::_CloseDataset(const char* pszFileName, GDALAccess eAccess) { GDALProxyPoolCacheEntry* cur = firstEntry; GIntBig responsiblePID = GDALGetResponsiblePIDForCurrentThread(); while(cur) { GDALProxyPoolCacheEntry* next = cur->next; CPLAssert(cur->pszFileName); if (strcmp(cur->pszFileName, pszFileName) == 0 && cur->refCount == 0 && cur->poDS != NULL ) { /* Close by pretending we are the thread that GDALOpen'ed this */ /* dataset */ GDALSetResponsiblePIDForCurrentThread(cur->responsiblePID); refCountOfDisableRefCount ++; GDALClose(cur->poDS); refCountOfDisableRefCount --; GDALSetResponsiblePIDForCurrentThread(responsiblePID); cur->poDS = NULL; cur->pszFileName[0] = '\0'; break; } cur = next; } }
CPL_C_END /* ******************************************************************** */ /* GDALProxyPoolDataset */ /* ******************************************************************** */ GDALProxyPoolDataset::GDALProxyPoolDataset(const char* pszSourceDatasetDescription, int nRasterXSize, int nRasterYSize, GDALAccess eAccess, int bShared, const char * pszProjectionRef, double * padfGeoTransform) { GDALDatasetPool::Ref(); SetDescription(pszSourceDatasetDescription); this->nRasterXSize = nRasterXSize; this->nRasterYSize = nRasterYSize; this->eAccess = eAccess; this->bShared = bShared; this->responsiblePID = GDALGetResponsiblePIDForCurrentThread(); if (pszProjectionRef) { this->pszProjectionRef = NULL; bHasSrcProjection = FALSE; } else { this->pszProjectionRef = CPLStrdup(pszProjectionRef); bHasSrcProjection = TRUE; } if (padfGeoTransform) { memcpy(adfGeoTransform, padfGeoTransform,6 * sizeof(double)); bHasSrcGeoTransform = TRUE; } else { adfGeoTransform[0] = 0; adfGeoTransform[1] = 1; adfGeoTransform[2] = 0; adfGeoTransform[3] = 0; adfGeoTransform[4] = 0; adfGeoTransform[5] = 1; bHasSrcGeoTransform = FALSE; } pszGCPProjection = NULL; nGCPCount = 0; pasGCPList = NULL; metadataSet = NULL; metadataItemSet = NULL; cacheEntry = NULL; }
GDALDatasetPool::~GDALDatasetPool() { GDALProxyPoolCacheEntry* cur = firstEntry; GIntBig responsiblePID = GDALGetResponsiblePIDForCurrentThread(); while(cur) { GDALProxyPoolCacheEntry* next = cur->next; CPLFree(cur->pszFileName); CPLAssert(cur->refCount == 0); if (cur->poDS) { GDALSetResponsiblePIDForCurrentThread(cur->responsiblePID); GDALClose(cur->poDS); } CPLFree(cur); cur = next; } GDALSetResponsiblePIDForCurrentThread(responsiblePID); }
CPL_C_END /* ******************************************************************** */ /* GDALProxyPoolDataset */ /* ******************************************************************** */ /* Note : the bShared parameter must be used with caution. You can */ /* set it to TRUE for being used as a VRT source : in that case, */ /* VRTSimpleSource will take care of destroying it when there are no */ /* reference to it (in VRTSimpleSource::~VRTSimpleSource()) */ /* However this will not be registered as a genuine shared dataset, like it */ /* would have been with MarkAsShared(). But MarkAsShared() is not usable for */ /* GDALProxyPoolDataset objects, as they share the same description as their */ /* underlying dataset. So *NEVER* call MarkAsShared() on a GDALProxyPoolDataset */ /* object */ GDALProxyPoolDataset::GDALProxyPoolDataset(const char* pszSourceDatasetDescription, int nRasterXSize, int nRasterYSize, GDALAccess eAccess, int bShared, const char * pszProjectionRef, double * padfGeoTransform) { GDALDatasetPool::Ref(); SetDescription(pszSourceDatasetDescription); this->nRasterXSize = nRasterXSize; this->nRasterYSize = nRasterYSize; this->eAccess = eAccess; this->bShared = bShared; this->responsiblePID = GDALGetResponsiblePIDForCurrentThread(); if (pszProjectionRef) { this->pszProjectionRef = NULL; bHasSrcProjection = FALSE; } else { this->pszProjectionRef = CPLStrdup(pszProjectionRef); bHasSrcProjection = TRUE; } if (padfGeoTransform) { memcpy(adfGeoTransform, padfGeoTransform,6 * sizeof(double)); bHasSrcGeoTransform = TRUE; } else { adfGeoTransform[0] = 0; adfGeoTransform[1] = 1; adfGeoTransform[2] = 0; adfGeoTransform[3] = 0; adfGeoTransform[4] = 0; adfGeoTransform[5] = 1; bHasSrcGeoTransform = FALSE; } pszGCPProjection = NULL; nGCPCount = 0; pasGCPList = NULL; metadataSet = NULL; metadataItemSet = NULL; cacheEntry = NULL; }
GDALProxyPoolCacheEntry* GDALDatasetPool::_RefDataset(const char* pszFileName, GDALAccess eAccess) { GDALProxyPoolCacheEntry* cur = firstEntry; GIntBig responsiblePID = GDALGetResponsiblePIDForCurrentThread(); GDALProxyPoolCacheEntry* lastEntryWithZeroRefCount = NULL; while(cur) { GDALProxyPoolCacheEntry* next = cur->next; if (strcmp(cur->pszFileName, pszFileName) == 0 && cur->responsiblePID == responsiblePID) { if (cur != firstEntry) { /* Move to begin */ if (cur->next) cur->next->prev = cur->prev; else lastEntry = cur->prev; cur->prev->next = cur->next; cur->prev = NULL; firstEntry->prev = cur; cur->next = firstEntry; firstEntry = cur; #ifdef DEBUG_PROXY_POOL CheckLinks(); #endif } cur->refCount ++; return cur; } if (cur->refCount == 0) lastEntryWithZeroRefCount = cur; cur = next; } if (currentSize == maxSize) { if (lastEntryWithZeroRefCount == NULL) { CPLError(CE_Failure, CPLE_AppDefined, "Too many threads are running for the current value of the dataset pool size (%d).\n" "or too many proxy datasets are opened in a cascaded way.\n" "Try increasing GDAL_MAX_DATASET_POOL_SIZE.", maxSize); return NULL; } CPLFree(lastEntryWithZeroRefCount->pszFileName); lastEntryWithZeroRefCount->pszFileName = NULL; if (lastEntryWithZeroRefCount->poDS) { /* Close by pretending we are the thread that GDALOpen'ed this */ /* dataset */ GDALSetResponsiblePIDForCurrentThread(lastEntryWithZeroRefCount->responsiblePID); refCountOfDisableRefCount ++; GDALClose(lastEntryWithZeroRefCount->poDS); refCountOfDisableRefCount --; lastEntryWithZeroRefCount->poDS = NULL; GDALSetResponsiblePIDForCurrentThread(responsiblePID); } /* Recycle this entry for the to-be-openeded dataset and */ /* moves it to the top of the list */ if (lastEntryWithZeroRefCount->prev) lastEntryWithZeroRefCount->prev->next = lastEntryWithZeroRefCount->next; else { CPLAssert(0); } if (lastEntryWithZeroRefCount->next) lastEntryWithZeroRefCount->next->prev = lastEntryWithZeroRefCount->prev; else { CPLAssert(lastEntryWithZeroRefCount == lastEntry); lastEntry->prev->next = NULL; lastEntry = lastEntry->prev; } lastEntryWithZeroRefCount->prev = NULL; lastEntryWithZeroRefCount->next = firstEntry; firstEntry->prev = lastEntryWithZeroRefCount; cur = firstEntry = lastEntryWithZeroRefCount; #ifdef DEBUG_PROXY_POOL CheckLinks(); #endif } else { /* Prepend */ cur = (GDALProxyPoolCacheEntry*) CPLMalloc(sizeof(GDALProxyPoolCacheEntry)); if (lastEntry == NULL) lastEntry = cur; cur->prev = NULL; cur->next = firstEntry; if (firstEntry) firstEntry->prev = cur; firstEntry = cur; currentSize ++; #ifdef DEBUG_PROXY_POOL CheckLinks(); #endif } cur->pszFileName = CPLStrdup(pszFileName); cur->responsiblePID = responsiblePID; cur->refCount = 1; refCountOfDisableRefCount ++; cur->poDS = (GDALDataset*) GDALOpen(pszFileName, eAccess); refCountOfDisableRefCount --; return cur; }