10117: Additional refinement: a directory not in use but still referenced needs
[arvados.git] / services / fuse / arvados_fuse / fresh.py
1 import time
2 import ciso8601
3 import calendar
4 import functools
5
6 def convertTime(t):
7     """Parse Arvados timestamp to unix time."""
8     if not t:
9         return 0
10     try:
11         return calendar.timegm(ciso8601.parse_datetime_unaware(t).timetuple())
12     except (TypeError, ValueError):
13         return 0
14
15 def use_counter(orig_func):
16     @functools.wraps(orig_func)
17     def use_counter_wrapper(self, *args, **kwargs):
18         try:
19             self.inc_use()
20             return orig_func(self, *args, **kwargs)
21         finally:
22             self.dec_use()
23     return use_counter_wrapper
24
25 def check_update(orig_func):
26     @functools.wraps(orig_func)
27     def check_update_wrapper(self, *args, **kwargs):
28         self.checkupdate()
29         return orig_func(self, *args, **kwargs)
30     return check_update_wrapper
31
32 class FreshBase(object):
33     """Base class for maintaining object lifecycle.
34
35     Functions include:
36
37     * Indicate if an object is up to date (stale() == false) or needs to be
38       updated sets stale() == True).  Use invalidate() to mark the object as
39       stale.  An object is also automatically stale if it has not been updated
40       in `_poll_time` seconds.
41
42     * Record access time (atime) timestamp
43
44     * Manage internal use count used by the inode cache ("inc_use" and
45       "dec_use").  An object which is in use cannot be cleared by the inode
46       cache.
47
48     * Manage the kernel reference count ("inc_ref" and "dec_ref").  An object
49       which is referenced by the kernel cannot have its inode entry deleted.
50
51     * Record cache footprint, cache priority
52
53     * Record Arvados uuid at the time the object is placed in the cache
54
55     * Clear the object contents (invalidates the object)
56
57     """
58     def __init__(self):
59         self._stale = True
60         self._poll = False
61         self._last_update = time.time()
62         self._atime = time.time()
63         self._poll_time = 60
64         self.use_count = 0
65         self.ref_count = 0
66         self.dead = False
67         self.cache_priority = None
68         self.cache_size = 0
69         self.cache_uuid = None
70         self.allow_attr_cache = True
71         self.allow_dirent_cache = True
72
73     # Mark the value as stale
74     def invalidate(self):
75         self._stale = True
76
77     # Test if the entries dict is stale.
78     def stale(self):
79         if self._stale:
80             return True
81         if self._poll:
82             return (self._last_update + self._poll_time) < self._atime
83         return False
84
85     def fresh(self):
86         self._stale = False
87         self._last_update = time.time()
88
89     def atime(self):
90         return self._atime
91
92     def persisted(self):
93         return False
94
95     def clear(self):
96         pass
97
98     def in_use(self):
99         return self.use_count > 0
100
101     def inc_use(self):
102         self.use_count += 1
103
104     def dec_use(self):
105         self.use_count -= 1
106
107     def inc_ref(self):
108         self.ref_count += 1
109         return self.ref_count
110
111     def dec_ref(self, n):
112         self.ref_count -= n
113         return self.ref_count
114
115     def has_ref(self, only_children=False):
116         return self.ref_count > 0
117
118     def objsize(self):
119         return 0
120
121     def uuid(self):
122         return None
123
124     def finalize(self):
125         pass