-
Notifications
You must be signed in to change notification settings - Fork 186
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Local response cache implementation (#1440)
* Basic cache implementation Signed-off-by: Sachin Varghese <[email protected]> * Setting max size to local cache implementation Signed-off-by: Sachin Varghese <[email protected]> * Adding lint fixes Signed-off-by: Sachin Varghese <[email protected]> * minor lint fix Signed-off-by: Sachin Varghese <[email protected]> * types update Signed-off-by: Sachin Varghese <[email protected]> * fixing tests Signed-off-by: Sachin Varghese <[email protected]> * optional typings updated Signed-off-by: Sachin Varghese <[email protected]> * cache impl refactor Signed-off-by: Sachin Varghese <[email protected]> * minor code refactor Signed-off-by: Sachin Varghese <[email protected]> * Adding basic handler cache tests Signed-off-by: Sachin Varghese <[email protected]> * Update cache tests Signed-off-by: Sachin Varghese <[email protected]> --------- Signed-off-by: Sachin Varghese <[email protected]>
- Loading branch information
1 parent
dbfa408
commit a94068b
Showing
13 changed files
with
215 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
from .cache import ResponseCache | ||
from .local import LocalCache | ||
|
||
__all__ = ["ResponseCache", "LocalCache"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
class ResponseCache: | ||
async def insert(self, key: str, value: str): | ||
""" | ||
Method responsible for inserting value to cache. | ||
**This method should be overriden to implement your custom cache logic.** | ||
""" | ||
raise NotImplementedError("insert() method not implemented") | ||
|
||
async def lookup(self, key: str) -> str: | ||
""" | ||
Method responsible for returning key value in the cache. | ||
**This method should be overriden to implement your custom cache logic.** | ||
""" | ||
raise NotImplementedError("lookup() method not implemented") | ||
|
||
async def size(self) -> int: | ||
""" | ||
Method responsible for returning the size of the cache. | ||
**This method should be overriden to implement your custom cache logic.** | ||
""" | ||
raise NotImplementedError("size() method not implemented") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from .local import LocalCache | ||
|
||
__all__ = ["LocalCache"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
from collections import OrderedDict | ||
from ..cache import ResponseCache | ||
|
||
|
||
class LocalCache(ResponseCache): | ||
def __init__(self, size=100): | ||
self.cache = OrderedDict() | ||
self.size_limit = size | ||
|
||
async def insert(self, key: str, value: str): | ||
self.cache[key] = value | ||
cache_size = await self.size() | ||
if cache_size > self.size_limit: | ||
# The cache removes the first entry if it overflows (i.e. in FIFO order) | ||
self.cache.popitem(last=False) | ||
return None | ||
|
||
async def lookup(self, key: str) -> str: | ||
if key in self.cache: | ||
return self.cache[key] | ||
else: | ||
return "" | ||
|
||
async def size(self) -> int: | ||
return len(self.cache) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import pytest | ||
|
||
from mlserver.cache.local import LocalCache | ||
from mlserver.cache import ResponseCache | ||
|
||
CACHE_SIZE = 10 | ||
|
||
|
||
@pytest.fixture | ||
def local_cache() -> ResponseCache: | ||
return LocalCache(size=CACHE_SIZE) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
from string import ascii_lowercase | ||
|
||
from .conftest import CACHE_SIZE | ||
|
||
|
||
async def test_local_cache_lookup(local_cache): | ||
assert await local_cache.size() == 0 | ||
assert await local_cache.lookup("unknown key") == "" | ||
assert await local_cache.size() == 0 | ||
|
||
|
||
async def test_local_cache_insert(local_cache): | ||
assert await local_cache.size() == 0 | ||
|
||
await local_cache.insert("key", "value") | ||
assert await local_cache.lookup("key") == "value" | ||
|
||
assert await local_cache.size() == 1 | ||
|
||
await local_cache.insert("new key", "new value") | ||
assert await local_cache.lookup("key") == "value" | ||
assert await local_cache.lookup("new key") == "new value" | ||
|
||
assert await local_cache.size() == 2 | ||
|
||
|
||
async def test_local_cache_rotate(local_cache): | ||
# Insert alphabets on a loop | ||
for key, symbol in enumerate(ascii_lowercase): | ||
await local_cache.insert(str(key), symbol) | ||
|
||
if key < CACHE_SIZE: | ||
assert await local_cache.size() == key + 1 | ||
assert await local_cache.lookup(str(key)) == symbol | ||
|
||
else: | ||
assert await local_cache.size() == CACHE_SIZE | ||
assert await local_cache.lookup(str(key)) == symbol | ||
assert await local_cache.lookup(str(key - CACHE_SIZE)) == "" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,31 @@ | ||
import pytest | ||
import os | ||
|
||
from mlserver.settings import Settings | ||
from mlserver.handlers import DataPlane | ||
from mlserver.handlers.custom import CustomHandler | ||
from mlserver.registry import MultiModelRegistry | ||
from prometheus_client.registry import CollectorRegistry | ||
|
||
from ..fixtures import SumModel | ||
from ..conftest import TESTDATA_PATH | ||
|
||
|
||
@pytest.fixture | ||
def custom_handler(sum_model: SumModel) -> CustomHandler: | ||
return CustomHandler(rest_path="/my-custom-endpoint") | ||
|
||
|
||
@pytest.fixture | ||
def cached_settings() -> Settings: | ||
settings_path = os.path.join(TESTDATA_PATH, "settings-cache.json") | ||
return Settings.parse_file(settings_path) | ||
|
||
|
||
@pytest.fixture | ||
def cached_data_plane( | ||
cached_settings: Settings, | ||
model_registry: MultiModelRegistry, | ||
prometheus_registry: CollectorRegistry, | ||
) -> DataPlane: | ||
return DataPlane(settings=cached_settings, model_registry=model_registry) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,5 +28,7 @@ | |
|
||
"parameters": { | ||
"version": "v1.2.3" | ||
} | ||
}, | ||
|
||
"cache_enabled": true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"debug": true, | ||
"host": "127.0.0.1", | ||
"parallel_workers": 2, | ||
"cors_settings": { | ||
"allow_origins": ["*"] | ||
}, | ||
"cache_enabled": true | ||
} |