void CCachedDirectory::RefreshStatus(bool bRecursive) { // Make sure that our own status is up-to-date GetStatusForMember(m_directoryPath,bRecursive); AutoLocker lock(m_critSec); // We also need to check if all our file members have the right date on them CacheEntryMap::iterator itMembers; std::set<CTGitPath> refreshedpaths; DWORD now = GetTickCount(); if (m_entryCache.empty()) return; for (itMembers = m_entryCache.begin(); itMembers != m_entryCache.end(); ++itMembers) { if (itMembers->first) { CTGitPath filePath(m_directoryPath); filePath.AppendPathString(itMembers->first); std::set<CTGitPath>::iterator refr_it; if ((!filePath.IsEquivalentToWithoutCase(m_directoryPath))&& (((refr_it = refreshedpaths.lower_bound(filePath)) == refreshedpaths.end()) || !filePath.IsEquivalentToWithoutCase(*refr_it))) { if ((itMembers->second.HasExpired(now))||(!itMembers->second.DoesFileTimeMatch(filePath.GetLastWriteTime()))) { lock.Unlock(); // We need to request this item as well GetStatusForMember(filePath,bRecursive); // GetStatusForMember now has recreated the m_entryCache map. // So start the loop again, but add this path to the refreshed paths set // to make sure we don't refresh this path again. This is to make sure // that we don't end up in an endless loop. lock.Lock(); refreshedpaths.insert(refr_it, filePath); itMembers = m_entryCache.begin(); if (m_entryCache.empty()) return; continue; } else if ((bRecursive)&&(itMembers->second.IsDirectory())) { // crawl all sub folders too! Otherwise a change deep inside the // tree which has changed won't get propagated up the tree. CGitStatusCache::Instance().AddFolderForCrawling(filePath); } } } } }
void CCachedDirectory::RefreshStatus(bool bRecursive) { // Make sure that our own status is up-to-date GetStatusForMember(m_directoryPath,bRecursive); CTSVNPathList updatePathList; CTSVNPathList crawlPathList; CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": RefreshStatus for %s\n"), m_directoryPath.GetWinPath()); DWORD now = GetTickCount(); { // get the file write times with FindFirstFile/FindNextFile since those // APIs only access the folder, not each file individually. // This reduces the disk access a *lot*. std::map<CStringA, ULONGLONG> filetimes; WIN32_FIND_DATA FindFileData; CAutoFindFile hFind = FindFirstFile(m_directoryPath.GetWinPathString() + L"\\*.*", &FindFileData); if (hFind) { while (FindNextFile(hFind, &FindFileData)) { if ( (wcscmp(FindFileData.cFileName, L"..")==0) || (wcscmp(FindFileData.cFileName, L".")==0) ) continue; ULARGE_INTEGER ft; ft.LowPart = FindFileData.ftLastWriteTime.dwLowDateTime; ft.HighPart = FindFileData.ftLastWriteTime.dwHighDateTime; CStringA nameUTF8 = CUnicodeUtils::GetUTF8(FindFileData.cFileName); filetimes[nameUTF8] = ft.QuadPart; } hFind.CloseHandle(); // explicit close handle to shorten its life time } AutoLocker lock(m_critSec); // We also need to check if all our file members have the right date on them for (CacheEntryMap::iterator itMembers = m_entryCache.begin(); itMembers != m_entryCache.end(); ++itMembers) { if ((itMembers->first)&&(!itMembers->first.IsEmpty())) { CTSVNPath filePath (GetFullPathString (itMembers->first)); if (!filePath.IsEquivalentToWithoutCase(m_directoryPath)) { // we only have file members in our entry cache ATLASSERT(!itMembers->second.IsDirectory()); auto ftIt = filetimes.find(itMembers->first.Mid(1)); if (ftIt != filetimes.end()) { ULONGLONG ft = ftIt->second; if ((itMembers->second.HasExpired(now))||(!itMembers->second.DoesFileTimeMatch(ft))) { // We need to request this item as well updatePathList.AddPath(filePath); } } } } } if (bRecursive) { // crawl all sub folders too! Otherwise a change deep inside the // tree which has changed won't get propagated up the tree. for(ChildDirStatus::const_iterator it = m_childDirectories.begin(); it != m_childDirectories.end(); ++it) { CTSVNPath path; CString winPath = CUnicodeUtils::GetUnicode (it->first); path.SetFromWin (winPath, true); crawlPathList.AddPath(path); } } } for (int i = 0; i < updatePathList.GetCount(); ++i) GetStatusForMember(updatePathList[i], bRecursive); for (int i = 0; i < crawlPathList.GetCount(); ++i) CSVNStatusCache::Instance().AddFolderForCrawling(crawlPathList[i]); }