[Scummvm-git-logs] scummvm master -> 606a7a3e792028ec34cfe13617053b739f6dc62a

sev- noreply at scummvm.org
Sun Dec 11 20:34:02 UTC 2022


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
606a7a3e79 COMMON: Make MemcachingCaseInsensitiveArchive configurably to use weak pointers


Commit: 606a7a3e792028ec34cfe13617053b739f6dc62a
    https://github.com/scummvm/scummvm/commit/606a7a3e792028ec34cfe13617053b739f6dc62a
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-12-11T21:33:59+01:00

Commit Message:
COMMON: Make MemcachingCaseInsensitiveArchive configurably to use weak pointers

This allows to keep memory footprint low on systems that are low on memory

Changed paths:
    common/archive.cpp
    common/archive.h


diff --git a/common/archive.cpp b/common/archive.cpp
index a61aa2fc331..cb76330791f 100644
--- a/common/archive.cpp
+++ b/common/archive.cpp
@@ -63,16 +63,42 @@ int Archive::listMatchingMembers(ArchiveMemberList &list, const Path &pattern) c
 
 SeekableReadStream *MemcachingCaseInsensitiveArchive::createReadStreamForMember(const Path &path) const {
 	String translated = translatePath(path);
+	bool isNew = false;
 	if (!_cache.contains(translated)) {
 		_cache[translated] = readContentsForPath(translated);
+		isNew = true;
 	}
 
-	const SharedArchiveContents& entry = _cache[translated];
+	SharedArchiveContents* entry = &_cache[translated];
 
-	if (entry.isFileMissing())
+	// Errors and missing files. Just return nullptr,
+	// no need to create stream.
+	if (entry->isFileMissing())
 		return nullptr;
 
-	return new Common::MemoryReadStream(entry.getContents(), entry.getSize());
+	// Check whether the entry is still valid as WeakPtr might have expired.
+	if (!entry->makeStrong()) {
+		// If it's expired, recreate the entry.
+		_cache[translated] = readContentsForPath(translated);
+		entry = &_cache[translated];
+		isNew = true;
+	}
+
+	// It's possible that recreation failed in case of e.g. network
+	// share going offline.
+	if (entry->isFileMissing())
+		return nullptr;
+
+	// Now we have a valid contents reference. Make stream for it.
+	Common::MemoryReadStream *memStream = new Common::MemoryReadStream(entry->getContents(), entry->getSize());
+
+	// If the entry was just created and it's too big for strong caching,
+	// mark the copy in cache as weak
+	if (isNew && entry->getSize() > _maxStronglyCachedSize) {
+		entry->makeWeak();
+	}
+
+	return memStream;
 }
 
 
diff --git a/common/archive.h b/common/archive.h
index 2e89a8e992f..b2a8546e623 100644
--- a/common/archive.h
+++ b/common/archive.h
@@ -141,19 +141,48 @@ public:
 	virtual SeekableReadStream *createReadStreamForMember(const Path &path) const = 0;
 };
 
+class MemcachingCaseInsensitiveArchive;
+
+// This is a shareable reference to a file contents stored in memory.
+// It can be in 2 states: strong when it holds a strong reference in
+// the sense of SharedPtr. Another state is weak when it only helds
+// WeakPtr and thus may expire. Also strong reference is held by
+// Returned memory stream. Hence once no memory streams and no
+// strong referenceas are remaining, the block is freed.
 class SharedArchiveContents {
 public:
-	SharedArchiveContents(byte *contents, uint32 contentSize) : _contents(contents, ArrayDeleter<byte>()), _contentSize(contentSize), _missingFile(false) {}
-	SharedArchiveContents() : _contents(nullptr), _contentSize(0), _missingFile(true) {}
+	SharedArchiveContents(byte *contents, uint32 contentSize) :
+		_strongRef(contents, ArrayDeleter<byte>()), _weakRef(_strongRef),
+		_contentSize(contentSize), _missingFile(false) {}
+	SharedArchiveContents() : _strongRef(nullptr), _weakRef(nullptr), _contentSize(0), _missingFile(true) {}
 
+private:
 	bool isFileMissing() const { return _missingFile; }
-	SharedPtr<byte> getContents() const { return _contents; }
+	SharedPtr<byte> getContents() const { return _strongRef; }
 	uint32 getSize() const { return _contentSize; }
 
-private:
-	SharedPtr<byte> _contents;
+	bool makeStrong() {
+		if (_strongRef || _contentSize == 0 || _missingFile)
+			return true;
+		_strongRef = SharedPtr<byte>(_weakRef);
+		if (_strongRef)
+			return true;
+		return false;
+	}
+
+	void makeWeak() {
+		// No need to make weak if we have no contents
+		if (_contentSize == 0)
+			return;
+		_strongRef = nullptr;
+	}
+
+	SharedPtr<byte> _strongRef;
+	WeakPtr<byte> _weakRef;
 	uint32 _contentSize;
 	bool _missingFile;
+
+	friend class MemcachingCaseInsensitiveArchive;
 };
 
 /**
@@ -161,6 +190,7 @@ private:
  */
 class MemcachingCaseInsensitiveArchive : public Archive {
 public:
+	MemcachingCaseInsensitiveArchive(uint32 maxStronglyCachedSize = 512) : _maxStronglyCachedSize(maxStronglyCachedSize) {}
 	SeekableReadStream *createReadStreamForMember(const Path &path) const;
 
 	virtual String translatePath(const Path &path) const {
@@ -173,6 +203,7 @@ public:
 
 private:
 	mutable HashMap<String, SharedArchiveContents, IgnoreCase_Hash, IgnoreCase_EqualTo> _cache;
+	uint32 _maxStronglyCachedSize;
 };
 
 /**




More information about the Scummvm-git-logs mailing list