aboutsummaryrefslogtreecommitdiff
path: root/src/zencompute/runners/deferreddeleter.h
blob: 9b010aa0f7ee8d7fdde40a1668451adcbc0bb58a (plain) (blame)
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
// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "zencompute/computeservice.h"

#if ZEN_WITH_COMPUTE_SERVICES

#	include <condition_variable>
#	include <deque>
#	include <filesystem>
#	include <mutex>
#	include <thread>
#	include <vector>

namespace zen::compute {

/// Deletes directories on a background thread to avoid blocking callers.
/// Useful when DeleteDirectories may stall (e.g. Wine's deferred-unlink semantics).
///
/// Enqueued directories wait for a deferral period before deletion, giving
/// file handles time to close. Call MarkReady() with the ActionLsn to shorten
/// the wait to a brief grace period (e.g. once a client has collected results).
/// On shutdown, all pending directories are deleted immediately.
class DeferredDirectoryDeleter
{
	DeferredDirectoryDeleter(const DeferredDirectoryDeleter&) = delete;
	DeferredDirectoryDeleter& operator=(const DeferredDirectoryDeleter&) = delete;

public:
	DeferredDirectoryDeleter();
	~DeferredDirectoryDeleter();

	/// Enqueue a directory for deferred deletion, associated with an action LSN.
	void Enqueue(int ActionLsn, std::filesystem::path Path);

	/// Signal that the action result has been consumed and the directory
	/// can be deleted after a short grace period instead of the full deferral.
	void MarkReady(int ActionLsn);

	/// Drain the queue and join the background thread. Idempotent.
	void Shutdown();

private:
	struct QueueEntry
	{
		int					  ActionLsn;
		std::filesystem::path Path;
	};

	std::mutex				m_Mutex;
	std::condition_variable m_Cv;
	std::deque<QueueEntry>	m_Queue;
	std::vector<int>		m_ReadyLsns;
	bool					m_Done = false;
	std::thread				m_Thread;
	void					ThreadFunction();
};

}  // namespace zen::compute

#endif

#if ZEN_WITH_TESTS
namespace zen::compute {
void deferreddeleter_forcelink();  // internal
}  // namespace zen::compute
#endif