summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2021-05-17 10:24:27 -0400
committerNat Goodspeed <nat@lindenlab.com>2021-05-17 10:24:27 -0400
commit87faf258911f5d23416500ff632050ce05b30e3e (patch)
tree120f10eb9097ed75d7cc7da95365670c1fb5b882 /indra
parent89cf988aaf0de402641cd945e7e9ad5292bc78d6 (diff)
SL-15200: Explain why purge() is called on another thread.
Also add Ansariel's explanation for why interaction through the filesystem itself should be safe.
Diffstat (limited to 'indra')
-rw-r--r--indra/llfilesystem/lldiskcache.cpp28
-rw-r--r--indra/llfilesystem/lldiskcache.h4
2 files changed, 31 insertions, 1 deletions
diff --git a/indra/llfilesystem/lldiskcache.cpp b/indra/llfilesystem/lldiskcache.cpp
index 17906ce369..c0f10ac620 100644
--- a/indra/llfilesystem/lldiskcache.cpp
+++ b/indra/llfilesystem/lldiskcache.cpp
@@ -53,6 +53,32 @@ LLDiskCache::LLDiskCache(const std::string cache_dir,
// WARNING: purge() is called by LLPurgeDiskCacheThread. As such it must
// NOT touch any LLDiskCache data without introducing and locking a mutex!
+
+// Interaction through the filesystem itself should be safe. Let’s say thread
+// A is accessing the cache file for reading/writing and thread B is trimming
+// the cache. Let’s also assume using llifstream to open a file and
+// boost::filesystem::remove are not atomic (which will be pretty much the
+// case).
+
+// Now, A is trying to open the file using llifstream ctor. It does some
+// checks if the file exists and whatever else it might be doing, but has not
+// issued the call to the OS to actually open the file yet. Now B tries to
+// delete the file: If the file has been already marked as in use by the OS,
+// deleting the file will fail and B will continue with the next file. A can
+// safely continue opening the file. If the file has not yet been marked as in
+// use, B will delete the file. Now A actually wants to open it, operation
+// will fail, subsequent check via llifstream.is_open will fail, asset will
+// have to be re-requested. (Assuming here the viewer will actually handle
+// this situation properly, that can also happen if there is a file containing
+// garbage.)
+
+// Other situation: B is trimming the cache and A wants to read a file that is
+// about to get deleted. boost::filesystem::remove does whatever it is doing
+// before actually deleting the file. If A opens the file before the file is
+// actually gone, the OS call from B to delete the file will fail since the OS
+// will prevent this. B continues with the next file. If the file is already
+// gone before A finally gets to open it, this operation will fail and the
+// asset will have to be re-requested.
void LLDiskCache::purge()
{
if (mEnableCacheDebugInfo)
@@ -358,4 +384,4 @@ void LLPurgeDiskCacheThread::run()
ms_sleep(100);
} while (!isQuitting());
-} \ No newline at end of file
+}
diff --git a/indra/llfilesystem/lldiskcache.h b/indra/llfilesystem/lldiskcache.h
index 7c5b798f7e..268fe92bcc 100644
--- a/indra/llfilesystem/lldiskcache.h
+++ b/indra/llfilesystem/lldiskcache.h
@@ -121,6 +121,10 @@ class LLDiskCache :
*
* WARNING: purge() is called by LLPurgeDiskCacheThread. As such it must
* NOT touch any LLDiskCache data without introducing and locking a mutex!
+ *
+ * Purging the disk cache involves nontrivial work on the viewer's
+ * filesystem. If called on the main thread, this causes a noticeable
+ * freeze.
*/
void purge();