AP: product dependency optimization (#6619)

* Initial pass at optimizing product path dependency resolution

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Add version of StripAssetPlatform that doesn't allocate or copy strings.  Re-add missing test and fix up compile errors.  Add benchmark test

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Change UpdateProductDependencies to directly call s_InsertProductDependencyQuery.BindAndStep

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Add test for same filename on multiple platforms

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Rework search logic to keep track of the source of a search path (source vs product) and keep track of which search matches which dependency to avoid doing another search through every product later on

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Clean up code, expand test

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Fix paths not being lowercased by SanitizeForDatabase.  Fix UpdateProductDependencies not updating existing dependencies

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Add test for duplicate dependency matches.  Fix saving duplicates

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Clean up code

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Separate test into test and benchmark versions

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Cleanup include

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Fix includes, switch hardcoded job manager setup to use JobManagerComponent instead

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Replaced wildcard_match with PathView::Match.  Changed StripAssetPlatformNoCopy to use TokenizeNext.  Removed Environment Create/Destroy calls.  Made ScopedAllocatorFixture a base class of ScopedAllocatorSetupFixture

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Add AZ Environment create/destroy on AP test environment

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Add missing asserts on database functions

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Fix incorrect usage of StripAssetPlatformNoCopy

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Fix source/product dependency type being ignored.  Removed need for unordered_set for list of resolved dependencies.  Updated unit tests

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Better variable names

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Remove testing code

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Fix missing includes and namespaces

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>
This commit is contained in:
amzn-mike
2022-01-13 08:56:24 -06:00
committed by GitHub
parent 6d1a2382e8
commit fed1278fe6
14 changed files with 742 additions and 237 deletions
@@ -48,7 +48,7 @@ namespace AssetProcessor
// note that this is not the first time we're opening the database - the main thread also opens it before this happens,
// which allows it to upgrade it and check it for errors. If we get here, it means the database is already good to go.
m_stateData->OpenDatabase();
m_stateData->OpenDatabase();
MigrateScanFolders();
@@ -70,7 +70,7 @@ namespace AssetProcessor
m_excludedFolderCache = AZStd::make_unique<ExcludedFolderCache>(m_platformConfig);
PopulateJobStateCache();
AssetProcessor::ProcessingJobInfoBus::Handler::BusConnect();
}
@@ -126,7 +126,7 @@ namespace AssetProcessor
{
// capture scanning stats:
AssetProcessor::StatsCapture::BeginCaptureStat("AssetScanning");
// Ensure that the source file list is populated before a scan begins
m_sourceFilesInDatabase.clear();
m_fileModTimes.clear();
@@ -155,11 +155,11 @@ namespace AssetProcessor
QString scanFolderPath;
QString relativeToScanFolderPath = QString::fromUtf8(entry.m_fileName.c_str());
for (int i = 0; i < m_platformConfig->GetScanFolderCount(); ++i)
{
const auto& scanFolderInfo = m_platformConfig->GetScanFolderAt(i);
if (scanFolderInfo.ScanFolderID() == entry.m_scanFolderPK)
{
scanFolderPath = scanFolderInfo.ScanPath();
@@ -181,7 +181,7 @@ namespace AssetProcessor
{
m_isCurrentlyScanning = false;
AssetProcessor::StatsCapture::EndCaptureStat("AssetScanning");
// we cannot invoke this immediately - the scanner might be done, but we aren't actually ready until we've processed all remaining messages:
QMetaObject::invokeMethod(this, "CheckMissingFiles", Qt::QueuedConnection);
}
@@ -216,7 +216,7 @@ namespace AssetProcessor
else
{
QString statKey = QString("ProcessJob,%1,%2,%3").arg(jobEntry.m_databaseSourceName).arg(jobEntry.m_jobKey).arg(jobEntry.m_platformInfo.m_identifier.c_str());
if (status == JobStatus::InProgress)
{
//update to in progress status
@@ -232,7 +232,7 @@ namespace AssetProcessor
// without going thru the RC.
// as such, all the code in this block should be crafted to work regardless of whether its double called.
AssetProcessor::StatsCapture::EndCaptureStat(statKey.toUtf8().constData());
m_jobRunKeyToJobInfoMap.erase(jobEntry.m_jobRunKey);
Q_EMIT SourceFinished(sourceUUID, legacySourceUUID);
Q_EMIT JobComplete(jobEntry, status);
@@ -308,7 +308,7 @@ namespace AssetProcessor
//! A network request came in, Given a Job Run Key (from the above Job Request), asking for the actual log for that job.
GetAbsoluteAssetDatabaseLocationResponse AssetProcessorManager::ProcessGetAbsoluteAssetDatabaseLocationRequest(MessageData<GetAbsoluteAssetDatabaseLocationRequest> messageData)
{
{
GetAbsoluteAssetDatabaseLocationResponse response;
AzToolsFramework::AssetDatabase::AssetDatabaseRequestsBus::Broadcast(&AzToolsFramework::AssetDatabase::AssetDatabaseRequests::GetAssetDatabaseLocation, response.m_absoluteAssetDatabaseLocation);
@@ -525,7 +525,7 @@ namespace AssetProcessor
{
foundOne = true;
return true;
},
},
AZ::Uuid::CreateNull(),
nullptr,
platform.toUtf8().constData(),
@@ -750,7 +750,7 @@ namespace AssetProcessor
}
OnJobStatusChanged(jobEntry, JobStatus::Failed);
// note that we always print out the failed job status here in both batch and GUI mode.
AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Failed %s, (%s)... \n",
jobEntry.m_pathRelativeToWatchFolder.toUtf8().constData(),
@@ -868,7 +868,7 @@ namespace AssetProcessor
&& AzFramework::StringFunc::Equal(job.m_platform.c_str(), itProcessedAsset->m_entry.m_platformInfo.m_identifier.c_str()))
{
// If we are here it implies that for the same source file we have another job that outputs the same product.
// This is usually the case when two builders process the same source file and outputs the same product file.
// This is usually the case when two builders process the same source file and outputs the same product file.
remove = true;
AZStd::string consoleMsg = AZStd::string::format("Failing Job (source : %s , jobkey %s) because another job (source : %s , jobkey : %s ) outputted the same product %s.\n",
itProcessedAsset->m_entry.m_pathRelativeToWatchFolder.toUtf8().constData(), itProcessedAsset->m_entry.m_jobKey.toUtf8().data(), source.m_sourceName.c_str(), job.m_jobKey.c_str(), newProductName.toUtf8().constData());
@@ -1128,7 +1128,7 @@ namespace AssetProcessor
QString fullProductPath = m_cacheRootDir.absoluteFilePath(productName);
// Strip the <asset_platform> from the front of a relative product path
QString relativeProductPath = AssetUtilities::StripAssetPlatform(priorProduct.m_productName);
AZStd::string_view relativeProductPath = AssetUtilities::StripAssetPlatformNoCopy(priorProduct.m_productName);
AZ::Data::AssetId assetId(source.m_sourceGuid, priorProduct.m_subID);
@@ -1137,7 +1137,7 @@ namespace AssetProcessor
AZ::Data::AssetId legacyAssetId(priorProduct.m_legacyGuid, 0);
AZ::Data::AssetId legacySourceAssetId(AssetUtilities::CreateSafeSourceUUIDFromName(source.m_sourceName.c_str(), false), priorProduct.m_subID);
AssetNotificationMessage message(relativeProductPath.toUtf8().constData(), AssetNotificationMessage::AssetRemoved, priorProduct.m_assetType, processedAsset.m_entry.m_platformInfo.m_identifier.c_str());
AssetNotificationMessage message(relativeProductPath, AssetNotificationMessage::AssetRemoved, priorProduct.m_assetType, processedAsset.m_entry.m_platformInfo.m_identifier.c_str());
message.m_assetId = assetId;
if (legacyAssetId != assetId)
@@ -1271,7 +1271,7 @@ namespace AssetProcessor
[&](AzToolsFramework::AssetDatabase::ProductDependencyDatabaseEntry& dependencyEntry)
{
return dependencyEntry.m_dependencySubID == pair.first.m_subID
&& dependencyEntry.m_dependencySourceGuid == source.m_sourceGuid;
&& dependencyEntry.m_dependencySourceGuid == source.m_sourceGuid;
});
if (conflictItr != dependencySet.end())
@@ -1312,14 +1312,14 @@ namespace AssetProcessor
// relative file path is gotten by removing the platform and game from the product name
// Strip the <asset_platform> from the front of a relative product path
QString relativeProductPath = AssetUtilities::StripAssetPlatform(productName.toUtf8().constData());
AZStd::string relativeProductPath = AssetUtilities::StripAssetPlatform(productName.toUtf8().constData()).toUtf8().constData();
AssetNotificationMessage message(relativeProductPath.toUtf8().constData(), AssetNotificationMessage::AssetChanged, newProduct.m_assetType, processedAsset.m_entry.m_platformInfo.m_identifier.c_str());
AssetNotificationMessage message(relativeProductPath, AssetNotificationMessage::AssetChanged, newProduct.m_assetType, processedAsset.m_entry.m_platformInfo.m_identifier.c_str());
AZ::Data::AssetId assetId(source.m_sourceGuid, newProduct.m_subID);
AZ::Data::AssetId legacyAssetId(newProduct.m_legacyGuid, 0);
AZ::Data::AssetId legacySourceAssetId(AssetUtilities::CreateSafeSourceUUIDFromName(source.m_sourceName.c_str(), false), newProduct.m_subID);
message.m_data = relativeProductPath.toUtf8().data();
message.m_data = relativeProductPath;
message.m_sizeBytes = QFileInfo(fullProductPath).size();
message.m_assetId = assetId;
@@ -1350,7 +1350,7 @@ namespace AssetProcessor
}
Q_EMIT AssetMessage( message);
AddKnownFoldersRecursivelyForFile(fullProductPath, m_cacheRootDir.absolutePath());
}
@@ -1497,7 +1497,7 @@ namespace AssetProcessor
// Record the modtime for the metadata file so we don't re-analyze this change again next time AP starts up
QFileInfo metadataFileInfo(originalName);
auto* scanFolder = m_platformConfig->GetScanFolderForFile(originalName);
if (scanFolder)
{
QString databaseName;
@@ -1534,7 +1534,7 @@ namespace AssetProcessor
for (const QString& absolutePath : absoluteSourcePathList)
{
// we need to check if its already in the "active files" (things that we are looking over)
// or if its in the "currently being examined" list. The latter is likely to be the smaller list,
// or if its in the "currently being examined" list. The latter is likely to be the smaller list,
// so we check it first. Both of those are absolute paths, so we convert to absolute path before
// searching those lists:
if (m_filesToExamine.find(absolutePath) != m_filesToExamine.end())
@@ -1633,9 +1633,6 @@ namespace AssetProcessor
}
}
// Strip the <asset_platform> from the front of a relative product path
QString relativePath = AssetUtilities::StripAssetPlatform(relativeProductFile.toUtf8().constData());
//set the fingerprint on the job that made this product
for (auto& job : jobs)
{
@@ -1678,7 +1675,7 @@ namespace AssetProcessor
}
QString fullProductPath = m_cacheRootDir.absoluteFilePath(product.m_productName.c_str());
QString relativeProductPath(AssetUtilities::StripAssetPlatform(product.m_productName));
AZStd::string_view relativeProductPath = AssetUtilities::StripAssetPlatformNoCopy(product.m_productName);
QFileInfo productFileInfo(fullProductPath);
if (productFileInfo.exists())
{
@@ -1725,7 +1722,7 @@ namespace AssetProcessor
AZ::Data::AssetId legacyAssetId(product.m_legacyGuid, 0);
AZ::Data::AssetId legacySourceAssetId(AssetUtilities::CreateSafeSourceUUIDFromName(source.m_sourceName.c_str(), false), product.m_subID);
AssetNotificationMessage message(relativeProductPath.toUtf8().constData(), AssetNotificationMessage::AssetRemoved, product.m_assetType, job.m_platform.c_str());
AssetNotificationMessage message(relativeProductPath, AssetNotificationMessage::AssetRemoved, product.m_assetType, job.m_platform.c_str());
message.m_assetId = assetId;
if (legacyAssetId != assetId)
@@ -1759,7 +1756,7 @@ namespace AssetProcessor
// and no overrides exist for it.
// we must delete its products.
using namespace AzToolsFramework::AssetDatabase;
// If we fail to delete a product, the deletion event gets requeued
// To avoid retrying forever, we keep track of the time of the first deletion failure and only retry
// if less than this amount of time has passed.
@@ -1832,7 +1829,7 @@ namespace AssetProcessor
{
return;
}
// Check if this file causes any file types to be re-evaluated
CheckMetaDataRealFiles(normalizedPath);
@@ -2046,7 +2043,7 @@ namespace AssetProcessor
AZ_TracePrintf(AssetProcessor::DebugChannel, "Non-processed file: %s\n", databaseSourceFile.toUtf8().constData());
++m_numSourcesNotHandledByAnyBuilder;
// Record the modtime for the file so we know we've already processed it
QString absolutePath = QDir(scanFolder->ScanPath()).absoluteFilePath(normalizedPath);
@@ -2114,7 +2111,7 @@ namespace AssetProcessor
// Check whether another job emitted this job as a job dependency and if true, queue the dependent job source file also
JobDesc jobDesc(jobDetails.m_jobEntry.m_databaseSourceName.toUtf8().data(),
jobDetails.m_jobEntry.m_jobKey.toUtf8().data(), jobDetails.m_jobEntry.m_platformInfo.m_identifier);
shouldProcessAsset = true;
QFileInfo file(jobDetails.m_jobEntry.GetAbsoluteSourcePath());
QDateTime dateTime(file.lastModified());
@@ -2347,7 +2344,7 @@ namespace AssetProcessor
}
QString canonicalRootDir = AssetUtilities::NormalizeFilePath(m_cacheRootDir.canonicalPath());
FileExamineContainer swapped;
m_filesToExamine.swap(swapped); // makes it okay to call CheckSource(...)
@@ -2470,7 +2467,7 @@ namespace AssetProcessor
AZ_TracePrintf(AssetProcessor::DebugChannel, "ProcessFilesToExamineQueue: Unable to find the relative path.\n");
continue;
}
const ScanFolderInfo* scanFolderInfo = m_platformConfig->GetScanFolderForFile(normalizedPath);
relativePathToFile = databasePathToFile;
@@ -2494,9 +2491,9 @@ namespace AssetProcessor
QString::fromUtf8(jobInfo.m_watchFolder.c_str()),
relativePathToFile,
databasePathToFile,
jobInfo.m_builderGuid,
*platformFromInfo,
jobInfo.m_jobKey.c_str(), 0, GenerateNewJobRunKey(),
jobInfo.m_builderGuid,
*platformFromInfo,
jobInfo.m_jobKey.c_str(), 0, GenerateNewJobRunKey(),
AZ::Uuid::CreateNull());
job.m_autoFail = true;
@@ -2597,7 +2594,7 @@ namespace AssetProcessor
{
// on the other hand, if we found a file it means that a deleted file revealed a file that
// was previously overridden by it.
// Because the deleted file may have "revealed" a file with different case,
// Because the deleted file may have "revealed" a file with different case,
// we have to actually correct its case here. This is rare, so it should be reasonable
// to call the expensive function to discover correct case.
QString pathRelativeToScanFolder;
@@ -2674,6 +2671,7 @@ namespace AssetProcessor
AZ_TracePrintf(ConsoleChannel, "Builder optimization: %i / %i files required full analysis, %i sources found but not processed by anyone\n", m_numSourcesNeedingFullAnalysis, m_numTotalSourcesFound, m_numSourcesNotHandledByAnyBuilder);
}
m_pathDependencyManager->ProcessQueuedDependencyResolves();
QTimer::singleShot(20, this, SLOT(RemoveEmptyFolders()));
}
else
@@ -2739,7 +2737,7 @@ namespace AssetProcessor
}
// over here we also want to invalidate the metafiles on disk map if it COULD Be a metafile
// note that there is no reason to do an expensive exacting computation here, it will be
// note that there is no reason to do an expensive exacting computation here, it will be
// done later and cached when m_cachedMetaFilesExistMap is set to false, we just need to
// know if its POSSIBLE that its a metafile, cheaply.
// if its a metafile match, then invalidate the metafile table.
@@ -2752,7 +2750,7 @@ namespace AssetProcessor
m_metaFilesWhichActuallyExistOnDisk.clear(); // invalidate the map, force a recompuation later.
}
}
}
m_AssetProcessorIsBusy = true;
@@ -2927,7 +2925,7 @@ namespace AssetProcessor
}
AZ::u64 fileHash = AssetUtilities::GetFileHash(fileInfo.m_filePath.toUtf8().constData());
if(fileHash != databaseHashValue)
{
// File contents have changed
@@ -3149,7 +3147,7 @@ namespace AssetProcessor
{
AddMetadataFilesForFingerprinting(kvp.first.c_str(), job.m_fingerprintFiles);
}
// Check the current builder jobs with the previous ones in the database:
job.m_jobEntry.m_computedFingerprint = AssetUtilities::GenerateFingerprint(job);
JobIndentifier jobIndentifier(JobDesc(job.m_jobEntry.m_databaseSourceName.toUtf8().data(), job.m_jobEntry.m_jobKey.toUtf8().data(), job.m_jobEntry.m_platformInfo.m_identifier), job.m_jobEntry.m_builderGuid);
@@ -3208,7 +3206,7 @@ namespace AssetProcessor
{
// If the database knows about the job than it implies that AP has processed it sucessfully at least once
// and therefore the dependent job should not cause the job which depends on it to be processed again.
// If however we find a dependent job which is not known to AP then we know this job needs to be processed
// If however we find a dependent job which is not known to AP then we know this job needs to be processed
// after all the dependent jobs have completed at least once.
AzToolsFramework::AssetDatabase::JobDatabaseEntryContainer jobs;
@@ -3238,7 +3236,7 @@ namespace AssetProcessor
}
else if(sourceFileDependency.m_sourceDependencyType != AssetBuilderSDK::SourceFileDependency::SourceFileDependencyType::Wildcards)
{
AZ_TracePrintf(AssetProcessor::ConsoleChannel, "UpdateJobDependency: Failed to find builder dependency for %s job (%s, %s, %s)\n",
AZ_TracePrintf(AssetProcessor::ConsoleChannel, "UpdateJobDependency: Failed to find builder dependency for %s job (%s, %s, %s)\n",
job.m_jobEntry.GetAbsoluteSourcePath().toUtf8().constData(),
jobDependencyInternal->m_jobDependency.m_sourceFile.m_sourceFileDependencyPath.c_str(),
jobDependencyInternal->m_jobDependency.m_jobKey.c_str(),
@@ -3262,7 +3260,7 @@ namespace AssetProcessor
++jobDependencySlot;
}
// sorting job dependencies as they can effect the fingerprint of the job
// sorting job dependencies as they can effect the fingerprint of the job
AZStd::sort(job.m_jobDependencyList.begin(), job.m_jobDependencyList.end(),
[](const AssetProcessor::JobDependencyInternal& lhs, const AssetProcessor::JobDependencyInternal& rhs)
{
@@ -3289,7 +3287,7 @@ namespace AssetProcessor
for (const JobDependencyInternal& jobDependencyInternal : job.m_jobDependencyList)
{
// Loop over all the builderUuid and check whether the corresponding entry exists in the jobsFingerprint map.
// If an entry exists, it implies than we have already send the job over to the RCController
// If an entry exists, it implies than we have already send the job over to the RCController
for (auto builderIter = jobDependencyInternal.m_builderUuidList.begin(); builderIter != jobDependencyInternal.m_builderUuidList.end(); ++builderIter)
{
JobIndentifier jobIdentifier(JobDesc(jobDependencyInternal.m_jobDependency.m_sourceFile.m_sourceFileDependencyPath,
@@ -3299,7 +3297,7 @@ namespace AssetProcessor
auto jobFound = m_jobFingerprintMap.find(jobIdentifier);
if (jobFound == m_jobFingerprintMap.end())
{
// Job cannot be processed, since one of its dependent job hasn't been fingerprinted
// Job cannot be processed, since one of its dependent job hasn't been fingerprinted
return false;
}
}
@@ -3317,7 +3315,7 @@ namespace AssetProcessor
// and call the CreateJobs function on the builder.
// it bundles the results up in a JobToProcessEntry struct, while it is doing this:
JobToProcessEntry entry;
AZ::Uuid sourceUUID = AssetUtilities::CreateSafeSourceUUIDFromName(databasePathToFile.toUtf8().constData());
// first, we put the source UUID in the map so that its present for any other queries:
@@ -3375,14 +3373,14 @@ namespace AssetProcessor
builderInfo.m_createJobFunction(createJobsRequest, createJobsResponse);
AssetProcessor::StatsCapture::EndCaptureStat(statKey.toUtf8().constData());
}
AssetProcessor::SetThreadLocalJobId(0);
bool isBuilderMissingFingerprint = (createJobsResponse.m_result == AssetBuilderSDK::CreateJobsResultCode::Success
&& !createJobsResponse.m_createJobOutputs.empty()
&& !createJobsResponse.m_createJobOutputs[0].m_additionalFingerprintInfo.empty()
&& builderInfo.m_analysisFingerprint.empty());
if (createJobsResponse.m_result == AssetBuilderSDK::CreateJobsResultCode::Failed || isBuilderMissingFingerprint)
{
AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Createjobs Failed: %s.\n", normalizedPath.toUtf8().constData());
@@ -3393,7 +3391,7 @@ namespace AssetProcessor
char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 };
AZ::IO::FileIOBase::GetInstance()->ResolvePath(fullPathToLogFile.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN);
JobDetails jobdetail;
jobdetail.m_jobEntry = JobEntry(
scanFolder->ScanPath(),
@@ -3486,9 +3484,9 @@ namespace AssetProcessor
scanFolder->ScanPath(),
actualRelativePath,
databasePathToFile,
builderInfo.m_busId,
*infoForPlatform,
jobDescriptor.m_jobKey.c_str(), 0, GenerateNewJobRunKey(),
builderInfo.m_busId,
*infoForPlatform,
jobDescriptor.m_jobKey.c_str(), 0, GenerateNewJobRunKey(),
sourceUUID);
newJob.m_jobEntry.m_checkExclusiveLock = jobDescriptor.m_checkExclusiveLock;
newJob.m_jobParam = AZStd::move(jobDescriptor.m_jobParameters);
@@ -3506,7 +3504,7 @@ namespace AssetProcessor
newJob.m_jobDependencyList.push_back(JobDependencyInternal(jobDependency));
++numJobDependencies;
}
// note that until analysis completes, the jobId is not set and neither is the destination pat
JobDesc jobDesc(newJob.m_jobEntry.m_databaseSourceName.toUtf8().data(), newJob.m_jobEntry.m_jobKey.toUtf8().data(), newJob.m_jobEntry.m_platformInfo.m_identifier);
m_jobDescToBuilderUuidMap[jobDesc].insert(builderInfo.m_busId);
@@ -3515,7 +3513,7 @@ namespace AssetProcessor
JobIndentifier jobIdentifier(jobDesc, builderInfo.m_busId);
{
AZStd::lock_guard<AssetProcessor::ProcessingJobInfoBus::MutexType> lock(AssetProcessor::ProcessingJobInfoBus::GetOrCreateContext().m_contextMutex);
m_jobFingerprintMap.erase(jobIdentifier);
m_jobFingerprintMap.erase(jobIdentifier);
}
entry.m_jobsToAnalyze.push_back(AZStd::move(newJob));
@@ -3578,7 +3576,7 @@ namespace AssetProcessor
// instead of a UUID, a path has been provided, prepare and use that. We need to turn it into a database path
QString encodedFileData = QString::fromUtf8(sourceDependency.m_sourceFileDependencyPath.c_str());
encodedFileData = AssetUtilities::NormalizeFilePath(encodedFileData);
if (sourceDependency.m_sourceDependencyType == AssetBuilderSDK::SourceFileDependency::SourceFileDependencyType::Wildcards)
{
int wildcardIndex = encodedFileData.indexOf("*");
@@ -3653,7 +3651,7 @@ namespace AssetProcessor
}
// Convert to relative paths
for (auto dependencyItr = resolvedDependencyList.begin(); dependencyItr != resolvedDependencyList.end();)
for (auto dependencyItr = resolvedDependencyList.begin(); dependencyItr != resolvedDependencyList.end();)
{
QString relativePath, scanFolder;
if (m_platformConfig->ConvertToRelativePath(*dependencyItr, relativePath, scanFolder))
@@ -3705,7 +3703,7 @@ namespace AssetProcessor
return (!resultDatabaseSourceName.isEmpty());
}
void AssetProcessorManager::UpdateSourceFileDependenciesDatabase(JobToProcessEntry& entry)
{
using namespace AzToolsFramework::AssetDatabase;
@@ -3738,7 +3736,7 @@ namespace AssetProcessor
QString resolvedDatabaseName;
if (!ResolveSourceFileDependencyPath(sourceDependency.second, resolvedDatabaseName,resolvedDependencyList))
{
// ResolveDependencyPath should only fail in a data error, otherwise it always outputs something,
// ResolveDependencyPath should only fail in a data error, otherwise it always outputs something,
// even if that something starts with the placeholder.
continue;
}
@@ -3759,7 +3757,7 @@ namespace AssetProcessor
SourceFileDependencyEntry newDependencyEntry(
sourceDependency.first,
entry.m_sourceFileInfo.m_databasePath.toUtf8().constData(),
resolvedDatabaseName.toUtf8().constData(),
resolvedDatabaseName.toUtf8().constData(),
sourceDependency.second.m_sourceDependencyType == AssetBuilderSDK::SourceFileDependency::SourceFileDependencyType::Wildcards ? SourceFileDependencyEntry::DEP_SourceLikeMatch : SourceFileDependencyEntry::DEP_SourceToSource,
!sourceDependency.second.m_sourceFileDependencyUUID.IsNull()); // If the UUID is null, then record that this dependency came from a (resolved) path
newDependencies.push_back(AZStd::move(newDependencyEntry));
@@ -3803,7 +3801,7 @@ namespace AssetProcessor
}
// get all the old dependencies and remove them. This function is comprehensive on all dependencies
// for a given source file so we can just eliminate all of them from that same source file and replace
// for a given source file so we can just eliminate all of them from that same source file and replace
// them with all of the new ones for the given source file:
AZStd::unordered_set<AZ::s64> oldDependencies;
m_stateData->QueryDependsOnSourceBySourceDependency(
@@ -4018,7 +4016,7 @@ namespace AssetProcessor
result.m_watchFolder = QString::fromUtf8(scanFolder.m_scanFolder.c_str());
result.m_sourceRelativeToWatchFolder = result.m_sourceDatabaseName;
{
{
// this scope exists to restrict the duration of the below lock.
AZStd::lock_guard<AZStd::mutex> lock(m_sourceUUIDToSourceInfoMapMutex);
m_sourceUUIDToSourceInfoMap.insert(AZStd::make_pair(sourceUuid, result));
@@ -4045,9 +4043,9 @@ namespace AssetProcessor
auto jobPair = m_jobsToProcess.insert(AZStd::move(jobDetail));
if (!jobPair.second)
{
// if we are here it means that this job was already found in the jobs to process list
// if we are here it means that this job was already found in the jobs to process list
// and therefore insert failed, we will try to update the iterator manually here.
// Note that if insert fails the original object is not destroyed and therefore we can use move again.
// Note that if insert fails the original object is not destroyed and therefore we can use move again.
// we just replaced a job, so we have to decrement its count.
UpdateAnalysisTrackerForFile(jobPair.first->m_jobEntry, AnalysisTrackerUpdateType::JobFinished);
@@ -4068,7 +4066,7 @@ namespace AssetProcessor
QSet<QString> absoluteSourceFilePathQueue;
QString databasePath;
QString scanFolder;
auto callbackFunction = [this, &absoluteSourceFilePathQueue](SourceFileDependencyEntry& entry)
{
QString relativeDatabaseName = QString::fromUtf8(entry.m_source.c_str());
@@ -4111,7 +4109,7 @@ namespace AssetProcessor
sourceDatabaseEntry.m_sourceName = relativeSourceFilePath.toUtf8().constData();
sourceDatabaseEntry.m_sourceGuid = AssetUtilities::CreateSafeSourceUUIDFromName(sourceDatabaseEntry.m_sourceName.c_str());
if (!m_stateData->SetSource(sourceDatabaseEntry))
{
AZ_Error(AssetProcessor::ConsoleChannel, false, "Failed to add source to the database!!!");
@@ -4260,7 +4258,7 @@ namespace AssetProcessor
{
AZ_TracePrintf(DebugChannel, "Builder %s analysis fingerprint changed. Files assigned to it will be re-analyzed.\n", priorBuilderUUID.ToString<AZStd::string>().c_str());
}
if (builderIsDirty)
{
m_anyBuilderChange = true;
@@ -4414,7 +4412,7 @@ namespace AssetProcessor
source.m_analysisFingerprint.append(builderFP.ToString<AZStd::string>());
}
m_pathDependencyManager->RetryDeferredDependencies(source);
m_pathDependencyManager->QueueSourceForDependencyResolution(source);
m_stateData->SetSource(source);
databaseSourceName = source.m_sourceName.c_str();
@@ -4593,7 +4591,7 @@ namespace AssetProcessor
{
continue;
}
QString firstMatchingFile = m_platformConfig->FindFirstMatchingFile(dep);
if (firstMatchingFile.isEmpty())
{
@@ -4787,7 +4785,7 @@ namespace AssetProcessor
assetIter->m_entry.m_sourceFileUUID);
jobdetail.m_autoFail = true;
jobdetail.m_critical = true;
jobdetail.m_priority = INT_MAX; // front of the queue.
jobdetail.m_priority = INT_MAX; // front of the queue.
jobdetail.m_scanFolder = m_platformConfig->GetScanFolderForFile(assetIter->m_entry.GetAbsoluteSourcePath());
// the new lines make it easier to copy and paste the file names.
jobdetail.m_jobParam[AZ_CRC(AutoFailReasonKey)] = autoFailReason;
@@ -4859,6 +4857,6 @@ namespace AssetProcessor
return filesFound;
}
} // namespace AssetProcessor