summaryrefslogtreecommitdiff
path: root/view/sharedcache/core/FileAccessorCache.h
blob: 46de6fcc773cdc554bb25302c65d96710e89494d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#pragma once

#include <shared_mutex>

#include "MappedFileAccessor.h"

typedef uint32_t CacheAccessorID;

// TODO: We might want to make this more than just the path, for example
// TODO: We might want to make it unique to a view session (session id).
// Get a unique entry id for the given file path.
CacheAccessorID GetCacheAccessorID(const std::string& filePath);

class WeakFileAccessor;

class FileAccessorCache
{
	size_t m_cacheSize;
	std::mutex m_mutex;
	// NOTE: If we end up wanting to handle 1000's of files we should consider std::list.
	std::deque<CacheAccessorID> m_cache;
	std::unordered_map<CacheAccessorID, std::shared_ptr<MappedFileAccessor>> m_accessors;

	explicit FileAccessorCache(size_t cacheSize = 8);

	void EvictLastUsed();

public:
	static FileAccessorCache& Global();

	// Get a weak reference to a file accessor, the reference at this point is alive.
	// The reference is always alive at this point either because it is in the cache or it has been inserted in.
	// Subsequent calls to this might kill the backing file accessor resulting in the weak ref recreating the file
	// accessor and inserting itself back into its related cache.
	WeakFileAccessor Open(const std::string& filePath);

	void RemoveAccessor(CacheAccessorID id);

	// Adjust the cache size limit.
	// This will NOT evict current cache entries, as they are already available.
	// Any subsequent call to `Open` will assume this cache size, evicting until the size is equal to the cache size.
	void SetCacheSize(const uint64_t size) { m_cacheSize = size; };

	size_t GetCacheSize() const { return m_cacheSize; }

	size_t GetCacheCount() const { return m_accessors.size(); }
};

class WeakFileAccessor
{
	using ReviveCallback = std::function<void(MappedFileAccessor&)>;

	// Weak pointer to the mapped file accessor, once this is expired we will re-open.
	std::weak_ptr<MappedFileAccessor> m_weakPtr;
	// File path for re-opening if needed
	std::string m_filePath;

	// Used to re-add writes once the file accessor is "revived".
	std::optional<ReviveCallback> m_reviveCallback;

	// TODO: Store a weak_ptr/shared_ptr to FileAccessorCache? That way we dont access Global()
	// TODO: Only need to do the above if we want multiple caches.

public:
	explicit WeakFileAccessor(std::weak_ptr<MappedFileAccessor> weakPtr, std::string filePath) :
		m_weakPtr(std::move(weakPtr)), m_filePath(std::move(filePath))
	{}

	// Register the function to be called once the file accessor is revived, this is typically
	// used to re-apply writes such as from slide info.
	void RegisterReviveCallback(const ReviveCallback& callback) {
		m_reviveCallback = callback;
	}

	std::shared_ptr<MappedFileAccessor> lock();
};