meta-memcache 2.0.0a1.dev6__tar.gz → 2.0.0a1.dev7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/PKG-INFO +2 -1
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/pyproject.toml +2 -1
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/__init__.py +1 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/commands/high_level_commands.py +8 -8
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/connection/memcache_socket.py +38 -27
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/executors/default.py +3 -2
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/extras/migrating_cache_client.py +5 -1
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/extras/probabilistic_hot_cache.py +4 -3
- meta_memcache-2.0.0a1.dev7/src/meta_memcache/protocol.py +177 -0
- meta_memcache-2.0.0a1.dev6/src/meta_memcache/protocol.py +0 -318
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/LICENSE +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/README.md +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/base/__init__.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/base/base_cache_client.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/base/base_serializer.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/cache_client.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/commands/__init__.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/commands/meta_commands.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/configuration.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/connection/__init__.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/connection/pool.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/connection/providers.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/errors.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/events/__init__.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/events/write_failure_event.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/executors/__init__.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/extras/__init__.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/extras/client_wrapper.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/interfaces/__init__.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/interfaces/cache_api.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/interfaces/commands.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/interfaces/executor.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/interfaces/high_level_commands.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/interfaces/meta_commands.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/interfaces/router.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/metrics/__init__.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/metrics/base.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/metrics/prometheus.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/py.typed +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/routers/__init__.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/routers/default.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/routers/ephemeral.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/routers/gutter.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/routers/helpers.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/serializer.py +0 -0
- {meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/settings.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: meta-memcache
|
|
3
|
-
Version: 2.0.0a1.
|
|
3
|
+
Version: 2.0.0a1.dev7
|
|
4
4
|
Summary: Modern, pure python, memcache client with support for new meta commands.
|
|
5
5
|
Home-page: https://github.com/RevenueCat/meta-memcache-py
|
|
6
6
|
License: MIT
|
|
@@ -14,6 +14,7 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
16
16
|
Requires-Dist: marisa-trie (>=1.0.0,<2.0.0)
|
|
17
|
+
Requires-Dist: meta-memcache-socket (>=0.1.0,<0.2.0)
|
|
17
18
|
Requires-Dist: uhashring (>=2.1,<3.0)
|
|
18
19
|
Project-URL: Repository, https://github.com/RevenueCat/meta-memcache-py
|
|
19
20
|
Description-Content-Type: text/markdown
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "meta-memcache"
|
|
3
|
-
version = "2.0.0a1-
|
|
3
|
+
version = "2.0.0a1-dev7"
|
|
4
4
|
description = "Modern, pure python, memcache client with support for new meta commands."
|
|
5
5
|
license = "MIT"
|
|
6
6
|
readme = "README.md"
|
|
@@ -14,6 +14,7 @@ packages = [{include = "meta_memcache", from="src"}]
|
|
|
14
14
|
python = "^3.8"
|
|
15
15
|
uhashring = "^2.1"
|
|
16
16
|
marisa-trie = "^1.0.0"
|
|
17
|
+
meta-memcache-socket = "^0.1.0"
|
|
17
18
|
|
|
18
19
|
[tool.poetry.group.extras.dependencies]
|
|
19
20
|
prometheus-client = "^0.17.1"
|
|
@@ -287,23 +287,23 @@ class HighLevelCommandsMixin:
|
|
|
287
287
|
|
|
288
288
|
if isinstance(result, Value):
|
|
289
289
|
# It is a hit.
|
|
290
|
-
if result.win:
|
|
290
|
+
if result.flags.win:
|
|
291
291
|
# Win flag present, meaning we got the lease to
|
|
292
292
|
# recache/cache the item. We need to mimic a miss.
|
|
293
|
-
return None, result.cas_token
|
|
294
|
-
if result.size == 0 and result.win is False:
|
|
293
|
+
return None, result.flags.cas_token
|
|
294
|
+
if result.size == 0 and result.flags.win is False:
|
|
295
295
|
# The value is empty, this is a miss lease,
|
|
296
296
|
# and we lost, so we must keep retrying and
|
|
297
|
-
# wait for the
|
|
297
|
+
# wait for the.flags.winner to populate the value.
|
|
298
298
|
if i < lease_policy.miss_retries:
|
|
299
299
|
continue
|
|
300
300
|
else:
|
|
301
301
|
# We run out of retries, behave as a miss
|
|
302
|
-
return None, result.cas_token
|
|
302
|
+
return None, result.flags.cas_token
|
|
303
303
|
else:
|
|
304
304
|
# There is data, either the is no lease or
|
|
305
305
|
# we lost and should use the stale value.
|
|
306
|
-
return result.value, result.cas_token
|
|
306
|
+
return result.value, result.flags.cas_token
|
|
307
307
|
else:
|
|
308
308
|
# With MISS_LEASE_TTL we should always get a value
|
|
309
309
|
# because on miss a lease empty value is generated
|
|
@@ -378,7 +378,7 @@ class HighLevelCommandsMixin:
|
|
|
378
378
|
if result is None:
|
|
379
379
|
return None, None
|
|
380
380
|
else:
|
|
381
|
-
return result.value, result.cas_token
|
|
381
|
+
return result.value, result.flags.cas_token
|
|
382
382
|
|
|
383
383
|
def _get(
|
|
384
384
|
self: HighLevelCommandMixinWithMetaCommands,
|
|
@@ -414,7 +414,7 @@ class HighLevelCommandsMixin:
|
|
|
414
414
|
) -> Optional[Value]:
|
|
415
415
|
if isinstance(result, Value):
|
|
416
416
|
# It is a hit
|
|
417
|
-
if result.win:
|
|
417
|
+
if result.flags.win:
|
|
418
418
|
# Win flag present, meaning we got the lease to
|
|
419
419
|
# recache the item. We need to mimic a miss, so
|
|
420
420
|
# we set the value to None.
|
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import socket
|
|
3
|
-
from typing import Union
|
|
3
|
+
from typing import Optional, Tuple, Union
|
|
4
|
+
|
|
5
|
+
import meta_memcache_socket
|
|
4
6
|
|
|
5
7
|
from meta_memcache.errors import MemcacheError
|
|
6
8
|
from meta_memcache.protocol import (
|
|
7
9
|
ENDL,
|
|
8
10
|
ENDL_LEN,
|
|
11
|
+
EMPTY_RESPONSE_FLAGS,
|
|
9
12
|
NOOP,
|
|
10
13
|
Conflict,
|
|
11
14
|
Miss,
|
|
12
15
|
NotStored,
|
|
13
16
|
ServerVersion,
|
|
14
17
|
Success,
|
|
18
|
+
ResponseFlags,
|
|
15
19
|
Value,
|
|
16
20
|
get_store_success_response_header,
|
|
17
21
|
)
|
|
@@ -119,7 +123,9 @@ class MemcacheSocket:
|
|
|
119
123
|
self._pos = 0
|
|
120
124
|
self._read = remaining_data
|
|
121
125
|
|
|
122
|
-
def _get_single_header(
|
|
126
|
+
def _get_single_header(
|
|
127
|
+
self,
|
|
128
|
+
) -> Tuple[int, Optional[int], Optional[int], Optional[ResponseFlags]]:
|
|
123
129
|
# Reset buffer for new data
|
|
124
130
|
if self._read == self._pos:
|
|
125
131
|
self._read = 0
|
|
@@ -127,22 +133,19 @@ class MemcacheSocket:
|
|
|
127
133
|
elif self._pos > self._reset_buffer_size:
|
|
128
134
|
self._reset_buffer()
|
|
129
135
|
|
|
130
|
-
endl_pos = -1
|
|
131
136
|
while True:
|
|
132
|
-
if self._read
|
|
133
|
-
|
|
134
|
-
if
|
|
135
|
-
|
|
137
|
+
if self._read != self._pos:
|
|
138
|
+
# We have data in the buffer: find the header
|
|
139
|
+
if header_data := meta_memcache_socket.parse_header(
|
|
140
|
+
self._buf_view, self._pos, self._read
|
|
141
|
+
):
|
|
142
|
+
self._pos = header_data[0]
|
|
143
|
+
return header_data
|
|
136
144
|
# Missing data, but still space in buffer, so read more
|
|
137
145
|
if self._recv_info_buffer() <= 0:
|
|
138
146
|
break
|
|
139
147
|
|
|
140
|
-
|
|
141
|
-
raise MemcacheError("Bad response. Socket might have closed unexpectedly")
|
|
142
|
-
|
|
143
|
-
pos = self._pos
|
|
144
|
-
self._pos = endl_pos + ENDL_LEN
|
|
145
|
-
return self._buf_view[pos:endl_pos]
|
|
148
|
+
raise MemcacheError("Bad response. Socket might have closed unexpectedly")
|
|
146
149
|
|
|
147
150
|
def sendall(self, data: bytes, with_noop: bool = False) -> None:
|
|
148
151
|
if with_noop:
|
|
@@ -153,10 +156,12 @@ class MemcacheSocket:
|
|
|
153
156
|
def _read_until_noop_header(self) -> None:
|
|
154
157
|
while self._noop_expected > 0:
|
|
155
158
|
header = self._get_single_header()
|
|
156
|
-
if header[
|
|
159
|
+
if header[1] == meta_memcache_socket.RESPONSE_NOOP:
|
|
157
160
|
self._noop_expected -= 1
|
|
158
161
|
|
|
159
|
-
def _get_header(
|
|
162
|
+
def _get_header(
|
|
163
|
+
self,
|
|
164
|
+
) -> Tuple[int, Optional[int], Optional[int], Optional[ResponseFlags]]:
|
|
160
165
|
try:
|
|
161
166
|
if self._noop_expected > 0:
|
|
162
167
|
self._read_until_noop_header()
|
|
@@ -169,30 +174,36 @@ class MemcacheSocket:
|
|
|
169
174
|
def get_response(
|
|
170
175
|
self,
|
|
171
176
|
) -> Union[Value, Success, NotStored, Conflict, Miss]:
|
|
172
|
-
|
|
173
|
-
response_code = header[0:2]
|
|
177
|
+
(_, response_code, size, flags) = self._get_header()
|
|
174
178
|
result: Union[Value, Success, NotStored, Conflict, Miss]
|
|
175
179
|
try:
|
|
176
|
-
if response_code ==
|
|
180
|
+
if response_code == meta_memcache_socket.RESPONSE_VALUE:
|
|
181
|
+
if size is None:
|
|
182
|
+
raise MemcacheError("Bad value response. Missing size")
|
|
177
183
|
# Value response
|
|
178
|
-
result = Value
|
|
179
|
-
|
|
184
|
+
result = Value(
|
|
185
|
+
size=size, flags=flags or EMPTY_RESPONSE_FLAGS, value=None
|
|
186
|
+
)
|
|
187
|
+
elif response_code == meta_memcache_socket.RESPONSE_SUCCESS:
|
|
180
188
|
# Stored or no value, return Success
|
|
181
|
-
result = Success
|
|
182
|
-
elif response_code ==
|
|
189
|
+
result = Success(flags=flags or EMPTY_RESPONSE_FLAGS)
|
|
190
|
+
elif response_code == meta_memcache_socket.RESPONSE_NOT_STORED:
|
|
183
191
|
# Value response, parse size and flags
|
|
184
192
|
result = NOT_STORED
|
|
185
|
-
elif response_code ==
|
|
193
|
+
elif response_code == meta_memcache_socket.RESPONSE_CONFLICT:
|
|
186
194
|
# Already exists, not changed, CAS conflict
|
|
187
195
|
result = CONFLICT
|
|
188
|
-
elif response_code ==
|
|
196
|
+
elif response_code == meta_memcache_socket.RESPONSE_MISS:
|
|
189
197
|
# Not Found, Miss.
|
|
190
198
|
result = MISS
|
|
191
199
|
else:
|
|
192
|
-
raise MemcacheError(f"Unknown response: {
|
|
200
|
+
raise MemcacheError(f"Unknown response: {response_code}")
|
|
193
201
|
except Exception as e:
|
|
194
|
-
_log.warning(
|
|
195
|
-
|
|
202
|
+
_log.warning(
|
|
203
|
+
f"Error parsing response header in {self}: "
|
|
204
|
+
f"Response: {response_code}, size {size}, flags: {flags}"
|
|
205
|
+
)
|
|
206
|
+
raise MemcacheError("Error parsing response header") from e
|
|
196
207
|
|
|
197
208
|
return result
|
|
198
209
|
|
{meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/executors/default.py
RENAMED
|
@@ -17,6 +17,7 @@ from meta_memcache.protocol import (
|
|
|
17
17
|
MetaCommand,
|
|
18
18
|
Miss,
|
|
19
19
|
NotStored,
|
|
20
|
+
ResponseFlags,
|
|
20
21
|
ServerVersion,
|
|
21
22
|
Success,
|
|
22
23
|
TokenFlag,
|
|
@@ -252,12 +253,12 @@ class DefaultExecutor:
|
|
|
252
253
|
Read response on a connection
|
|
253
254
|
"""
|
|
254
255
|
if flags and Flag.NOREPLY in flags:
|
|
255
|
-
return Success()
|
|
256
|
+
return Success(flags=ResponseFlags())
|
|
256
257
|
result = conn.get_response()
|
|
257
258
|
if isinstance(result, Value):
|
|
258
259
|
data = conn.get_value(result.size)
|
|
259
260
|
if result.size > 0:
|
|
260
|
-
encoding_id = result.client_flag or 0
|
|
261
|
+
encoding_id = result.flags.client_flag or 0
|
|
261
262
|
try:
|
|
262
263
|
result.value = self._serializer.unserialize(data, encoding_id)
|
|
263
264
|
except Exception:
|
|
@@ -78,7 +78,11 @@ class MigratingCacheClient(HighLevelCommandsMixin):
|
|
|
78
78
|
return current_mode
|
|
79
79
|
|
|
80
80
|
def _get_value_ttl(self, value: Value) -> int:
|
|
81
|
-
ttl =
|
|
81
|
+
ttl = (
|
|
82
|
+
value.flags.ttl
|
|
83
|
+
if value.flags.ttl is not None
|
|
84
|
+
else self._default_read_backfill_ttl
|
|
85
|
+
)
|
|
82
86
|
if ttl < 0:
|
|
83
87
|
# TTL for items marked to store forvered is returned as -1
|
|
84
88
|
ttl = 0
|
|
@@ -124,10 +124,11 @@ class ProbabilisticHotCache(ClientWrapper):
|
|
|
124
124
|
allowed: bool,
|
|
125
125
|
) -> None:
|
|
126
126
|
if not is_hot:
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
last_read_age = (
|
|
128
|
+
value.flags.last_access if value.flags.last_access is not None else 9999
|
|
129
|
+
)
|
|
129
130
|
if (
|
|
130
|
-
|
|
131
|
+
value.flags.fetched
|
|
131
132
|
and last_read_age <= self._max_last_access_age_seconds
|
|
132
133
|
):
|
|
133
134
|
# Is detected as hot
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from enum import Enum, IntEnum
|
|
3
|
+
from typing import Any, Dict, List, Optional, Union
|
|
4
|
+
|
|
5
|
+
from meta_memcache_socket import ResponseFlags
|
|
6
|
+
|
|
7
|
+
ENDL = b"\r\n"
|
|
8
|
+
NOOP: bytes = b"mn" + ENDL
|
|
9
|
+
ENDL_LEN = 2
|
|
10
|
+
SPACE: int = ord(" ")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class Key:
|
|
15
|
+
__slots__ = ("key", "routing_key", "is_unicode")
|
|
16
|
+
key: str
|
|
17
|
+
routing_key: Optional[str]
|
|
18
|
+
is_unicode: bool
|
|
19
|
+
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
key: str,
|
|
23
|
+
routing_key: Optional[str] = None,
|
|
24
|
+
is_unicode: bool = False,
|
|
25
|
+
) -> None:
|
|
26
|
+
self.key = key
|
|
27
|
+
self.routing_key = routing_key
|
|
28
|
+
self.is_unicode = is_unicode
|
|
29
|
+
|
|
30
|
+
def __hash__(self) -> int:
|
|
31
|
+
return hash((self.key, self.routing_key))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class MetaCommand(Enum):
|
|
35
|
+
META_GET = b"mg" # Meta Get
|
|
36
|
+
META_SET = b"ms" # Meta Set
|
|
37
|
+
META_DELETE = b"md" # Meta Delete
|
|
38
|
+
META_ARITHMETIC = b"ma" # Meta Arithmetic
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class SetMode(Enum):
|
|
42
|
+
SET = b"S" # Default
|
|
43
|
+
ADD = b"E" # Add if item does NOT EXIST, else LRU bump and return NS
|
|
44
|
+
APPEND = b"A" # If item exists, append the new value to its data.
|
|
45
|
+
PREPEND = b"P" # If item exists, prepend the new value to its data.
|
|
46
|
+
REPLACE = b"R" # Set only if item already exists.
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class Flag(Enum):
|
|
50
|
+
BINARY = b"b"
|
|
51
|
+
NOREPLY = b"q"
|
|
52
|
+
RETURN_CLIENT_FLAG = b"f"
|
|
53
|
+
RETURN_CAS_TOKEN = b"c"
|
|
54
|
+
RETURN_VALUE = b"v"
|
|
55
|
+
RETURN_TTL = b"t"
|
|
56
|
+
RETURN_SIZE = b"s"
|
|
57
|
+
RETURN_LAST_ACCESS = b"l"
|
|
58
|
+
RETURN_FETCHED = b"h"
|
|
59
|
+
RETURN_KEY = b"k"
|
|
60
|
+
NO_UPDATE_LRU = b"u"
|
|
61
|
+
MARK_STALE = b"I"
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class IntFlag(Enum):
|
|
65
|
+
CACHE_TTL = b"T"
|
|
66
|
+
RECACHE_TTL = b"R"
|
|
67
|
+
MISS_LEASE_TTL = b"N"
|
|
68
|
+
SET_CLIENT_FLAG = b"F"
|
|
69
|
+
MA_INITIAL_VALUE = b"J"
|
|
70
|
+
MA_DELTA_VALUE = b"D"
|
|
71
|
+
CAS_TOKEN = b"C"
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class TokenFlag(Enum):
|
|
75
|
+
OPAQUE = b"O"
|
|
76
|
+
# 'M' (mode switch):
|
|
77
|
+
# * Meta Arithmetic:
|
|
78
|
+
# - I or +: increment
|
|
79
|
+
# - D or -: decrement
|
|
80
|
+
# * Meta Set: See SetMode Enum above
|
|
81
|
+
# - E: "add" command. LRU bump and return NS if item exists. Else add.
|
|
82
|
+
# - A: "append" command. If item exists, append the new value to its data.
|
|
83
|
+
# - P: "prepend" command. If item exists, prepend the new value to its data.
|
|
84
|
+
# - R: "replace" command. Set only if item already exists.
|
|
85
|
+
# - S: "set" command. The default mode, added for completeness.
|
|
86
|
+
MODE = b"M"
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
# Store maps of byte values (int) to enum value
|
|
90
|
+
flag_values: Dict[int, Flag] = {f.value[0]: f for f in Flag}
|
|
91
|
+
int_flags_values: Dict[int, IntFlag] = {f.value[0]: f for f in IntFlag}
|
|
92
|
+
token_flags_values: Dict[int, TokenFlag] = {f.value[0]: f for f in TokenFlag}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@dataclass
|
|
96
|
+
class MemcacheResponse:
|
|
97
|
+
__slots__ = ()
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@dataclass
|
|
101
|
+
class Miss(MemcacheResponse):
|
|
102
|
+
__slots__ = ()
|
|
103
|
+
|
|
104
|
+
pass
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# Response flags
|
|
108
|
+
EMPTY_RESPONSE_FLAGS = ResponseFlags()
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@dataclass
|
|
112
|
+
class Success(MemcacheResponse):
|
|
113
|
+
__slots__ = ("flags",)
|
|
114
|
+
flags: ResponseFlags
|
|
115
|
+
|
|
116
|
+
@classmethod
|
|
117
|
+
def default(cls) -> "Success":
|
|
118
|
+
return cls(flags=ResponseFlags())
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@dataclass
|
|
122
|
+
class Value(Success):
|
|
123
|
+
__slots__ = ("flags", "size", "value")
|
|
124
|
+
size: int
|
|
125
|
+
value: Optional[Any]
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@dataclass
|
|
129
|
+
class ValueContainer:
|
|
130
|
+
__slots__ = ("value",)
|
|
131
|
+
value: Any
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
MaybeValue = Optional[ValueContainer]
|
|
135
|
+
MaybeValues = Optional[List[ValueContainer]]
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
@dataclass
|
|
139
|
+
class NotStored(MemcacheResponse):
|
|
140
|
+
__slots__ = ()
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@dataclass
|
|
144
|
+
class Conflict(MemcacheResponse):
|
|
145
|
+
__slots__ = ()
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
ReadResponse = Union[Miss, Value, Success]
|
|
149
|
+
WriteResponse = Union[Success, NotStored, Conflict, Miss]
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
Blob = Union[bytes, bytearray, memoryview]
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class ServerVersion(IntEnum):
|
|
156
|
+
"""
|
|
157
|
+
If more versions with breaking changes are
|
|
158
|
+
added, bump stable to the next int. Code
|
|
159
|
+
will be able to use > / < / = to code
|
|
160
|
+
the behavior of the different versions.
|
|
161
|
+
"""
|
|
162
|
+
|
|
163
|
+
AWS_1_6_6 = 1
|
|
164
|
+
STABLE = 2
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def get_store_success_response_header(version: ServerVersion) -> bytes:
|
|
168
|
+
if version == ServerVersion.AWS_1_6_6:
|
|
169
|
+
return b"OK"
|
|
170
|
+
return b"HD"
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def encode_size(size: int, version: ServerVersion) -> bytes:
|
|
174
|
+
if version == ServerVersion.AWS_1_6_6:
|
|
175
|
+
return b"S" + str(size).encode("ascii")
|
|
176
|
+
else:
|
|
177
|
+
return str(size).encode("ascii")
|
|
@@ -1,318 +0,0 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
2
|
-
from enum import Enum, IntEnum
|
|
3
|
-
from typing import Any, Dict, List, Optional, Union
|
|
4
|
-
|
|
5
|
-
ENDL = b"\r\n"
|
|
6
|
-
NOOP: bytes = b"mn" + ENDL
|
|
7
|
-
ENDL_LEN = 2
|
|
8
|
-
SPACE: int = ord(" ")
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@dataclass
|
|
12
|
-
class Key:
|
|
13
|
-
__slots__ = ("key", "routing_key", "is_unicode")
|
|
14
|
-
key: str
|
|
15
|
-
routing_key: Optional[str]
|
|
16
|
-
is_unicode: bool
|
|
17
|
-
|
|
18
|
-
def __init__(
|
|
19
|
-
self,
|
|
20
|
-
key: str,
|
|
21
|
-
routing_key: Optional[str] = None,
|
|
22
|
-
is_unicode: bool = False,
|
|
23
|
-
) -> None:
|
|
24
|
-
self.key = key
|
|
25
|
-
self.routing_key = routing_key
|
|
26
|
-
self.is_unicode = is_unicode
|
|
27
|
-
|
|
28
|
-
def __hash__(self) -> int:
|
|
29
|
-
return hash((self.key, self.routing_key))
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class MetaCommand(Enum):
|
|
33
|
-
META_GET = b"mg" # Meta Get
|
|
34
|
-
META_SET = b"ms" # Meta Set
|
|
35
|
-
META_DELETE = b"md" # Meta Delete
|
|
36
|
-
META_ARITHMETIC = b"ma" # Meta Arithmetic
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
class SetMode(Enum):
|
|
40
|
-
SET = b"S" # Default
|
|
41
|
-
ADD = b"E" # Add if item does NOT EXIST, else LRU bump and return NS
|
|
42
|
-
APPEND = b"A" # If item exists, append the new value to its data.
|
|
43
|
-
PREPEND = b"P" # If item exists, prepend the new value to its data.
|
|
44
|
-
REPLACE = b"R" # Set only if item already exists.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
class Flag(Enum):
|
|
48
|
-
BINARY = b"b"
|
|
49
|
-
NOREPLY = b"q"
|
|
50
|
-
RETURN_CLIENT_FLAG = b"f"
|
|
51
|
-
RETURN_CAS_TOKEN = b"c"
|
|
52
|
-
RETURN_VALUE = b"v"
|
|
53
|
-
RETURN_TTL = b"t"
|
|
54
|
-
RETURN_SIZE = b"s"
|
|
55
|
-
RETURN_LAST_ACCESS = b"l"
|
|
56
|
-
RETURN_FETCHED = b"h"
|
|
57
|
-
RETURN_KEY = b"k"
|
|
58
|
-
NO_UPDATE_LRU = b"u"
|
|
59
|
-
MARK_STALE = b"I"
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
class IntFlag(Enum):
|
|
63
|
-
CACHE_TTL = b"T"
|
|
64
|
-
RECACHE_TTL = b"R"
|
|
65
|
-
MISS_LEASE_TTL = b"N"
|
|
66
|
-
SET_CLIENT_FLAG = b"F"
|
|
67
|
-
MA_INITIAL_VALUE = b"J"
|
|
68
|
-
MA_DELTA_VALUE = b"D"
|
|
69
|
-
CAS_TOKEN = b"C"
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
class TokenFlag(Enum):
|
|
73
|
-
OPAQUE = b"O"
|
|
74
|
-
# 'M' (mode switch):
|
|
75
|
-
# * Meta Arithmetic:
|
|
76
|
-
# - I or +: increment
|
|
77
|
-
# - D or -: decrement
|
|
78
|
-
# * Meta Set: See SetMode Enum above
|
|
79
|
-
# - E: "add" command. LRU bump and return NS if item exists. Else add.
|
|
80
|
-
# - A: "append" command. If item exists, append the new value to its data.
|
|
81
|
-
# - P: "prepend" command. If item exists, prepend the new value to its data.
|
|
82
|
-
# - R: "replace" command. Set only if item already exists.
|
|
83
|
-
# - S: "set" command. The default mode, added for completeness.
|
|
84
|
-
MODE = b"M"
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
# Store maps of byte values (int) to enum value
|
|
88
|
-
flag_values: Dict[int, Flag] = {f.value[0]: f for f in Flag}
|
|
89
|
-
int_flags_values: Dict[int, IntFlag] = {f.value[0]: f for f in IntFlag}
|
|
90
|
-
token_flags_values: Dict[int, TokenFlag] = {f.value[0]: f for f in TokenFlag}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
@dataclass
|
|
94
|
-
class MemcacheResponse:
|
|
95
|
-
__slots__ = ()
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
@dataclass
|
|
99
|
-
class Miss(MemcacheResponse):
|
|
100
|
-
__slots__ = ()
|
|
101
|
-
|
|
102
|
-
pass
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
# Response flags
|
|
106
|
-
TOKEN_FLAG_OPAQUE = ord("O")
|
|
107
|
-
INT_FLAG_CAS_TOKEN = ord("c")
|
|
108
|
-
INT_FLAG_FETCHED = ord("h")
|
|
109
|
-
INT_FLAG_LAST_ACCESS = ord("l")
|
|
110
|
-
INT_FLAG_TTL = ord("t")
|
|
111
|
-
INT_FLAG_CLIENT_FLAG = ord("f")
|
|
112
|
-
INT_FLAG_SIZE = ord("s")
|
|
113
|
-
FLAG_WIN = ord("W")
|
|
114
|
-
FLAG_LOST = ord("Z")
|
|
115
|
-
FLAG_STALE = ord("X")
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
# @dataclass(slots=True, init=False)
|
|
119
|
-
@dataclass
|
|
120
|
-
class Success(MemcacheResponse):
|
|
121
|
-
__slots__ = (
|
|
122
|
-
"cas_token",
|
|
123
|
-
"fetched",
|
|
124
|
-
"last_access",
|
|
125
|
-
"ttl",
|
|
126
|
-
"client_flag",
|
|
127
|
-
"win",
|
|
128
|
-
"stale",
|
|
129
|
-
"real_size",
|
|
130
|
-
"opaque",
|
|
131
|
-
)
|
|
132
|
-
cas_token: Optional[int]
|
|
133
|
-
fetched: Optional[int]
|
|
134
|
-
last_access: Optional[int]
|
|
135
|
-
ttl: Optional[int]
|
|
136
|
-
client_flag: Optional[int]
|
|
137
|
-
win: Optional[bool]
|
|
138
|
-
stale: bool
|
|
139
|
-
real_size: Optional[int]
|
|
140
|
-
opaque: Optional[bytes]
|
|
141
|
-
|
|
142
|
-
def __init__(
|
|
143
|
-
self,
|
|
144
|
-
*,
|
|
145
|
-
cas_token: Optional[int] = None,
|
|
146
|
-
fetched: Optional[int] = None,
|
|
147
|
-
last_access: Optional[int] = None,
|
|
148
|
-
ttl: Optional[int] = None,
|
|
149
|
-
client_flag: Optional[int] = None,
|
|
150
|
-
win: Optional[bool] = None,
|
|
151
|
-
stale: bool = False,
|
|
152
|
-
real_size: Optional[int] = None,
|
|
153
|
-
opaque: Optional[bytes] = None,
|
|
154
|
-
) -> None:
|
|
155
|
-
self.cas_token = cas_token
|
|
156
|
-
self.fetched = fetched
|
|
157
|
-
self.last_access = last_access
|
|
158
|
-
self.ttl = ttl
|
|
159
|
-
self.client_flag = client_flag
|
|
160
|
-
self.win = win
|
|
161
|
-
self.stale = stale
|
|
162
|
-
self.real_size = real_size
|
|
163
|
-
self.opaque = opaque
|
|
164
|
-
|
|
165
|
-
@classmethod
|
|
166
|
-
def from_header(cls, header: "Blob") -> "Success":
|
|
167
|
-
result = cls()
|
|
168
|
-
result._set_flags(header)
|
|
169
|
-
return result
|
|
170
|
-
|
|
171
|
-
def _set_flags(self, header: bytes, pos: int = 3) -> None: # noqa: C901
|
|
172
|
-
header_size = len(header)
|
|
173
|
-
while pos < header_size:
|
|
174
|
-
flag = header[pos]
|
|
175
|
-
pos += 1
|
|
176
|
-
if flag == SPACE:
|
|
177
|
-
continue
|
|
178
|
-
end = pos
|
|
179
|
-
while end < header_size:
|
|
180
|
-
if header[end] == SPACE:
|
|
181
|
-
break
|
|
182
|
-
end += 1
|
|
183
|
-
|
|
184
|
-
if flag == INT_FLAG_CAS_TOKEN:
|
|
185
|
-
self.cas_token = int(header[pos:end])
|
|
186
|
-
elif flag == INT_FLAG_FETCHED:
|
|
187
|
-
self.fetched = int(header[pos:end])
|
|
188
|
-
elif flag == INT_FLAG_LAST_ACCESS:
|
|
189
|
-
self.last_access = int(header[pos:end])
|
|
190
|
-
elif flag == INT_FLAG_TTL:
|
|
191
|
-
self.ttl = int(header[pos:end])
|
|
192
|
-
elif flag == INT_FLAG_CLIENT_FLAG:
|
|
193
|
-
self.client_flag = int(header[pos:end])
|
|
194
|
-
elif flag == FLAG_WIN:
|
|
195
|
-
self.win = True
|
|
196
|
-
elif flag == FLAG_LOST:
|
|
197
|
-
self.win = False
|
|
198
|
-
elif flag == FLAG_STALE:
|
|
199
|
-
self.stale = True
|
|
200
|
-
elif flag == INT_FLAG_SIZE:
|
|
201
|
-
self.real_size = int(header[pos:end])
|
|
202
|
-
elif flag == TOKEN_FLAG_OPAQUE:
|
|
203
|
-
self.opaque = header[pos:end]
|
|
204
|
-
pos = end + 1
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
# @dataclass(slots=True, init=False)
|
|
208
|
-
@dataclass
|
|
209
|
-
class Value(Success):
|
|
210
|
-
__slots__ = (
|
|
211
|
-
"cas_token",
|
|
212
|
-
"fetched",
|
|
213
|
-
"last_access",
|
|
214
|
-
"ttl",
|
|
215
|
-
"client_flag",
|
|
216
|
-
"win",
|
|
217
|
-
"stale",
|
|
218
|
-
"real_size",
|
|
219
|
-
"opaque",
|
|
220
|
-
"size",
|
|
221
|
-
"value",
|
|
222
|
-
)
|
|
223
|
-
size: int
|
|
224
|
-
value: Optional[Any]
|
|
225
|
-
|
|
226
|
-
def __init__(
|
|
227
|
-
self,
|
|
228
|
-
*,
|
|
229
|
-
size: int,
|
|
230
|
-
value: Optional[Any] = None,
|
|
231
|
-
cas_token: Optional[int] = None,
|
|
232
|
-
fetched: Optional[int] = None,
|
|
233
|
-
last_access: Optional[int] = None,
|
|
234
|
-
ttl: Optional[int] = None,
|
|
235
|
-
client_flag: Optional[int] = None,
|
|
236
|
-
win: Optional[bool] = None,
|
|
237
|
-
stale: bool = False,
|
|
238
|
-
real_size: Optional[int] = None,
|
|
239
|
-
opaque: Optional[bytes] = None,
|
|
240
|
-
) -> None:
|
|
241
|
-
self.size = size
|
|
242
|
-
self.value = value
|
|
243
|
-
self.cas_token = cas_token
|
|
244
|
-
self.fetched = fetched
|
|
245
|
-
self.last_access = last_access
|
|
246
|
-
self.ttl = ttl
|
|
247
|
-
self.client_flag = client_flag
|
|
248
|
-
self.win = win
|
|
249
|
-
self.stale = stale
|
|
250
|
-
self.real_size = real_size
|
|
251
|
-
self.opaque = opaque
|
|
252
|
-
|
|
253
|
-
@classmethod
|
|
254
|
-
def from_header(cls, header: "Blob") -> "Value":
|
|
255
|
-
header_size = len(header)
|
|
256
|
-
if header_size < 4 or header[2] != SPACE:
|
|
257
|
-
raise ValueError(f"Invalid header {header!r}")
|
|
258
|
-
end = 4
|
|
259
|
-
while end < header_size:
|
|
260
|
-
if header[end] == SPACE:
|
|
261
|
-
break
|
|
262
|
-
end += 1
|
|
263
|
-
size = int(header[3:end])
|
|
264
|
-
result = cls(size=size)
|
|
265
|
-
result._set_flags(header, pos=end + 1)
|
|
266
|
-
return result
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
@dataclass
|
|
270
|
-
class ValueContainer:
|
|
271
|
-
__slots__ = ("value",)
|
|
272
|
-
value: Any
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
MaybeValue = Optional[ValueContainer]
|
|
276
|
-
MaybeValues = Optional[List[ValueContainer]]
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
@dataclass
|
|
280
|
-
class NotStored(MemcacheResponse):
|
|
281
|
-
__slots__ = ()
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
@dataclass
|
|
285
|
-
class Conflict(MemcacheResponse):
|
|
286
|
-
__slots__ = ()
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
ReadResponse = Union[Miss, Value, Success]
|
|
290
|
-
WriteResponse = Union[Success, NotStored, Conflict, Miss]
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
Blob = Union[bytes, bytearray, memoryview]
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
class ServerVersion(IntEnum):
|
|
297
|
-
"""
|
|
298
|
-
If more versions with breaking changes are
|
|
299
|
-
added, bump stable to the next int. Code
|
|
300
|
-
will be able to use > / < / = to code
|
|
301
|
-
the behavior of the different versions.
|
|
302
|
-
"""
|
|
303
|
-
|
|
304
|
-
AWS_1_6_6 = 1
|
|
305
|
-
STABLE = 2
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
def get_store_success_response_header(version: ServerVersion) -> bytes:
|
|
309
|
-
if version == ServerVersion.AWS_1_6_6:
|
|
310
|
-
return b"OK"
|
|
311
|
-
return b"HD"
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
def encode_size(size: int, version: ServerVersion) -> bytes:
|
|
315
|
-
if version == ServerVersion.AWS_1_6_6:
|
|
316
|
-
return b"S" + str(size).encode("ascii")
|
|
317
|
-
else:
|
|
318
|
-
return str(size).encode("ascii")
|
|
File without changes
|
|
File without changes
|
{meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/base/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/base/base_serializer.py
RENAMED
|
File without changes
|
|
File without changes
|
{meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/commands/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/configuration.py
RENAMED
|
File without changes
|
{meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/connection/__init__.py
RENAMED
|
File without changes
|
{meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/connection/pool.py
RENAMED
|
File without changes
|
{meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/connection/providers.py
RENAMED
|
File without changes
|
|
File without changes
|
{meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/events/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/executors/__init__.py
RENAMED
|
File without changes
|
{meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/extras/__init__.py
RENAMED
|
File without changes
|
{meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/extras/client_wrapper.py
RENAMED
|
File without changes
|
{meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/interfaces/__init__.py
RENAMED
|
File without changes
|
{meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/interfaces/cache_api.py
RENAMED
|
File without changes
|
{meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/interfaces/commands.py
RENAMED
|
File without changes
|
{meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/interfaces/executor.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/interfaces/router.py
RENAMED
|
File without changes
|
{meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/metrics/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/metrics/prometheus.py
RENAMED
|
File without changes
|
|
File without changes
|
{meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/routers/__init__.py
RENAMED
|
File without changes
|
{meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/routers/default.py
RENAMED
|
File without changes
|
{meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/routers/ephemeral.py
RENAMED
|
File without changes
|
{meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/routers/gutter.py
RENAMED
|
File without changes
|
{meta_memcache-2.0.0a1.dev6 → meta_memcache-2.0.0a1.dev7}/src/meta_memcache/routers/helpers.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|