21700: Install Bundler system-wide in Rails postinst
[arvados.git] / services / fuse / arvados_fuse / fresh.py
1 # Copyright (C) The Arvados Authors. All rights reserved.
2 #
3 # SPDX-License-Identifier: AGPL-3.0
4
5 from builtins import object
6 import time
7 import ciso8601
8 import calendar
9 import functools
10
11 def convertTime(t):
12     """Parse Arvados timestamp to unix time."""
13     if not t:
14         return 0
15     try:
16         return calendar.timegm(ciso8601.parse_datetime_as_naive(t).timetuple())
17     except (TypeError, ValueError):
18         return 0
19
20 def use_counter(orig_func):
21     @functools.wraps(orig_func)
22     def use_counter_wrapper(self, *args, **kwargs):
23         try:
24             self.inc_use()
25             return orig_func(self, *args, **kwargs)
26         finally:
27             self.dec_use()
28     return use_counter_wrapper
29
30 def check_update(orig_func):
31     @functools.wraps(orig_func)
32     def check_update_wrapper(self, *args, **kwargs):
33         self.checkupdate()
34         return orig_func(self, *args, **kwargs)
35     return check_update_wrapper
36
37 class FreshBase(object):
38     """Base class for maintaining object lifecycle.
39
40     Functions include:
41
42     * Indicate if an object is up to date (stale() == false) or needs to be
43       updated sets stale() == True).  Use invalidate() to mark the object as
44       stale.  An object is also automatically stale if it has not been updated
45       in `_poll_time` seconds.
46
47     * Record access time (atime) timestamp
48
49     * Manage internal use count used by the inode cache ("inc_use" and
50       "dec_use").  An object which is in use cannot be cleared by the inode
51       cache.
52
53     * Manage the kernel reference count ("inc_ref" and "dec_ref").  An object
54       which is referenced by the kernel cannot have its inode entry deleted.
55
56     * Record cache footprint, cache priority
57
58     * Record Arvados uuid at the time the object is placed in the cache
59
60     * Clear the object contents (invalidates the object)
61
62     """
63
64     __slots__ = ("_stale", "_poll", "_last_update", "_atime", "_poll_time", "use_count",
65                  "ref_count", "cache_size", "cache_uuid", "allow_attr_cache")
66
67     def __init__(self):
68         self._stale = True
69         self._poll = False
70         self._last_update = time.time()
71         self._atime = time.time()
72         self._poll_time = 60
73         self.use_count = 0
74         self.ref_count = 0
75         self.cache_size = 0
76         self.cache_uuid = None
77
78         # Can the kernel cache attributes?
79         self.allow_attr_cache = True
80
81     def invalidate(self):
82         """Indicate that object contents should be refreshed from source."""
83         self._stale = True
84
85     def kernel_invalidate(self):
86         """Indicate that an invalidation for this object should be sent to the kernel."""
87         pass
88
89     # Test if the entries dict is stale.
90     def stale(self):
91         if self._stale:
92             return True
93         if self._poll:
94             return (self._last_update + self._poll_time) < self._atime
95         return False
96
97     def fresh(self):
98         self._stale = False
99         self._last_update = time.time()
100
101     def atime(self):
102         return self._atime
103
104     def persisted(self):
105         return False
106
107     def clear(self):
108         pass
109
110     def in_use(self):
111         return self.use_count > 0
112
113     def inc_use(self):
114         self.use_count += 1
115
116     def dec_use(self):
117         self.use_count -= 1
118
119     def inc_ref(self):
120         self.ref_count += 1
121         return self.ref_count
122
123     def dec_ref(self, n):
124         self.ref_count -= n
125         return self.ref_count
126
127     def has_ref(self):
128         """Determine if there are any kernel references to this
129         object.
130         """
131         return self.ref_count > 0
132
133     def objsize(self):
134         return 0
135
136     def uuid(self):
137         return None
138
139     def finalize(self):
140         pass
141
142     def child_event(self, ev):
143         pass
144
145     def time_to_next_poll(self):
146         if self._poll:
147             t = (self._last_update + self._poll_time) - self._atime
148             if t < 0:
149                 return 0
150             else:
151                 return t
152         else:
153             return self._poll_time