@@ -19,8 +19,10 @@ class UWSGISplitStorage(SplitStorage):
1919
2020 _KEY_TEMPLATE = 'split.{suffix}'
2121 _KEY_TILL = 'splits.till'
22- _KEY_FEATURE_LIST_LOCK = 'splits.list.lock'
2322 _KEY_FEATURE_LIST = 'splits.list'
23+ _KEY_FEATURE_LIST_LOCK = 'splits.list.lock'
24+ _KEY_TRAFFIC_TYPES = 'splits.traffic_types'
25+ _KEY_TRAFFIC_TYPES_LOCK = 'splits.traffic_types.lock'
2426 _OVERWRITE_LOCK_SECONDS = 5
2527
2628 def __init__ (self , uwsgi_entrypoint ):
@@ -64,21 +66,8 @@ def put(self, split):
6466 0 ,
6567 _SPLITIO_SPLITS_CACHE_NAMESPACE
6668 )
67-
68- with UWSGILock (self ._uwsgi , self ._KEY_FEATURE_LIST_LOCK ):
69- try :
70- current = set (json .loads (
71- self ._uwsgi .cache_get (self ._KEY_FEATURE_LIST , _SPLITIO_MISC_NAMESPACE )
72- ))
73- except TypeError :
74- current = set ()
75- current .add (split .name )
76- self ._uwsgi .cache_update (
77- self ._KEY_FEATURE_LIST ,
78- json .dumps (list (current )),
79- 0 ,
80- _SPLITIO_MISC_NAMESPACE
81- )
69+ self ._add_split_to_list (split .name )
70+ self ._increase_traffic_type_count (split .traffic_type_name )
8271
8372 def remove (self , split_name ):
8473 """
@@ -90,31 +79,23 @@ def remove(self, split_name):
9079 :return: True if the split was found and removed. False otherwise.
9180 :rtype: bool
9281 """
93- with UWSGILock (self ._uwsgi , self ._KEY_FEATURE_LIST_LOCK ):
94- try :
95- current = set (json .loads (
96- self ._uwsgi .cache_get (self ._KEY_FEATURE_LIST , _SPLITIO_MISC_NAMESPACE )
97- ))
98- current .remove (split_name )
99- self ._uwsgi .cache_update (
100- self ._KEY_FEATURE_LIST ,
101- json .dumps (list (current )),
102- 0 ,
103- _SPLITIO_MISC_NAMESPACE
104- )
105- except TypeError :
106- # Split list not found, no need to delete anything
107- pass
108- except KeyError :
109- # Split not found in list. nothing to do.
110- pass
82+ # We need to fetch the split to get the traffic type name prior to deleting.
83+ fetched = self .get (split_name )
84+ if fetched is None :
85+ self ._logger .warning (
86+ "Tried to remove feature \" %s\" not present in cache. Ignoring." , split_name
87+ )
88+ return
11189
11290 result = self ._uwsgi .cache_del (
11391 self ._KEY_TEMPLATE .format (suffix = split_name ),
11492 _SPLITIO_SPLITS_CACHE_NAMESPACE
11593 )
11694 if not result is False :
117- self ._logger .warning ("Trying to retrieve nonexistant split %s. Ignoring." , split_name )
95+ self ._logger .warning ("Trying to delete nonexistant split %s. Ignoring." , split_name )
96+
97+ self ._remove_split_from_list (split_name )
98+ self ._decrease_traffic_type_count (fetched .traffic_type_name )
11899 return result
119100
120101 def get_change_number (self ):
@@ -162,6 +143,116 @@ def get_all_splits(self):
162143 """
163144 return [self .get (split_name ) for split_name in self .get_split_names ()]
164145
146+ def is_valid_traffic_type (self , traffic_type_name ):
147+ """
148+ Return whether the traffic type exists in at least one split in cache.
149+
150+ :param traffic_type_name: Traffic type to validate.
151+ :type traffic_type_name: str
152+
153+ :return: True if the traffic type is valid. False otherwise.
154+ :rtype: bool
155+ """
156+ try :
157+ tts = json .loads (
158+ self ._uwsgi .cache_get (self ._KEY_TRAFFIC_TYPES , _SPLITIO_MISC_NAMESPACE )
159+ )
160+ return traffic_type_name in tts
161+ except TypeError :
162+ return False
163+
164+ def _add_split_to_list (self , split_name ):
165+ """
166+ Add a specific split to the list we keep track of.
167+
168+ :param split_name: Name of the split to add.
169+ :type split_name: str
170+ """
171+ with UWSGILock (self ._uwsgi , self ._KEY_FEATURE_LIST_LOCK ):
172+ try :
173+ current = set (json .loads (
174+ self ._uwsgi .cache_get (self ._KEY_FEATURE_LIST , _SPLITIO_MISC_NAMESPACE )
175+ ))
176+ except TypeError :
177+ current = set ()
178+ current .add (split_name )
179+ self ._uwsgi .cache_update (
180+ self ._KEY_FEATURE_LIST ,
181+ json .dumps (list (current )),
182+ 0 ,
183+ _SPLITIO_MISC_NAMESPACE
184+ )
185+
186+ def _remove_split_from_list (self , split_name ):
187+ """
188+ Remove a specific split from the list we keep track of.
189+
190+ :param split_name: Name of the split to remove.
191+ :type split_name: str
192+ """
193+ with UWSGILock (self ._uwsgi , self ._KEY_FEATURE_LIST_LOCK ):
194+ try :
195+ current = set (json .loads (
196+ self ._uwsgi .cache_get (self ._KEY_FEATURE_LIST , _SPLITIO_MISC_NAMESPACE )
197+ ))
198+ current .remove (split_name )
199+ self ._uwsgi .cache_update (
200+ self ._KEY_FEATURE_LIST ,
201+ json .dumps (list (current )),
202+ 0 ,
203+ _SPLITIO_MISC_NAMESPACE
204+ )
205+ except TypeError :
206+ # Split list not found, no need to delete anything
207+ pass
208+ except KeyError :
209+ # Split not found in list. nothing to do.
210+ pass
211+
212+ def _increase_traffic_type_count (self , traffic_type_name ):
213+ """
214+ Increase by 1 the count for a specific traffic type.
215+
216+ :param traffic_type_name: Traffic type name to increase count.
217+ :type traffic_type_name: str
218+ """
219+ with UWSGILock (self ._uwsgi , self ._KEY_TRAFFIC_TYPES_LOCK ):
220+ try :
221+ tts = json .loads (
222+ self ._uwsgi .cache_get (self ._KEY_TRAFFIC_TYPES , _SPLITIO_MISC_NAMESPACE )
223+ )
224+ tts [traffic_type_name ] = tts .get (traffic_type_name , 0 ) + 1
225+
226+ except TypeError :
227+ tts = {traffic_type_name : 1 }
228+
229+ self ._uwsgi .cache_update (
230+ self ._KEY_TRAFFIC_TYPES , json .dumps (tts ), 0 , _SPLITIO_MISC_NAMESPACE
231+ )
232+
233+ def _decrease_traffic_type_count (self , traffic_type_name ):
234+ """
235+ Decreaase by 1 the count for a specific traffic type.
236+
237+ :param traffic_type_name: Traffic type name to decrease count.
238+ :type traffic_type_name: str
239+ """
240+ with UWSGILock (self ._uwsgi , self ._KEY_TRAFFIC_TYPES_LOCK ):
241+ try :
242+ tts = json .loads (
243+ self ._uwsgi .cache_get (self ._KEY_TRAFFIC_TYPES , _SPLITIO_MISC_NAMESPACE )
244+ )
245+ tts [traffic_type_name ] = tts .get (traffic_type_name , 0 ) - 1
246+ if tts [traffic_type_name ] <= 0 :
247+ del tts [traffic_type_name ]
248+ except TypeError :
249+ # Traffic type list not present. nothing to do here.
250+ return
251+
252+ self ._uwsgi .cache_update (
253+ self ._KEY_TRAFFIC_TYPES , json .dumps (tts ), 0 , _SPLITIO_MISC_NAMESPACE
254+ )
255+
165256
166257class UWSGISegmentStorage (SegmentStorage ):
167258 """UWSGI-Cache based implementation of a split storage."""
0 commit comments