Skip to content

Commit

Permalink
update core API and release 0.4.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Yiling-J committed Mar 19, 2023
1 parent ad4cd19 commit abc468f
Show file tree
Hide file tree
Showing 11 changed files with 58 additions and 54 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
# Changelog
All notable changes to this project will be documented in this file.

## [0.4.0]
### Added
- Add policy option to Django settings
### Changed
- Update core API


## [0.3.3]
### Added
- Clock-PRO policy
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ CACHES = {
"default": {
"BACKEND": "theine.adapters.django.Cache",
"TIMEOUT": 300,
"OPTIONS": {"MAX_ENTRIES": 10000},
"OPTIONS": {"MAX_ENTRIES": 10000, "POLICY": "tlfu"},
},
}
```
Expand Down
6 changes: 3 additions & 3 deletions benchmarks/benchmark_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
import uuid
from typing import List

import pytest
import cacheout
from cachetools import LFUCache, cached, LRUCache

import pytest
from bounded_zipf import Zipf
from cachetools import LFUCache, LRUCache, cached

from theine.thenie import Cache, Memoize

REQUESTS = 10000
Expand Down
6 changes: 3 additions & 3 deletions benchmarks/trace_bench.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import csv
from time import sleep
import matplotlib.pyplot as plt
from datetime import timedelta
from functools import lru_cache
from random import randint
from time import sleep
from typing import Callable, Iterable
from unittest.mock import Mock

from cachetools import LFUCache, cached
import matplotlib.pyplot as plt
from bounded_zipf import Zipf
from cachetools import LFUCache, cached

from theine import Cache, Memoize

Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
[tool.poetry]
name = "theine"
version = "0.3.3"
version = "0.4.0"
description = "high performance in-memory cache"
authors = ["Yiling-J <[email protected]>"]
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.7"
typing-extensions = "^4.4.0"
theine-core = "^0.3.3"
theine-core = "^0.4.0"

[tool.poetry.group.dev.dependencies]
pytest = "^7.2.1"
Expand Down
2 changes: 1 addition & 1 deletion tests/adapters/settings/theine.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"default": {
"BACKEND": "theine.adapters.django.Cache",
"TIMEOUT": 60,
"OPTIONS": {"MAX_ENTRIES": 1000},
"OPTIONS": {"MAX_ENTRIES": 1000, "POLICY": "tlfu"},
},
}

Expand Down
7 changes: 4 additions & 3 deletions tests/test_cache.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import pytest
from datetime import timedelta
from random import randint
from time import sleep

import pytest

from theine.thenie import Cache, sentinel


Expand Down Expand Up @@ -46,7 +47,7 @@ def test_set_with_ttl(policy):
cache = Cache(policy, 500)
for i in range(30):
key = f"key:{i}"
cache.set(key, key, timedelta(seconds=i))
cache.set(key, key, timedelta(seconds=i + 1))
key = f"key:{i}:2"
cache.set(key, key, timedelta(seconds=i + 100))
assert len(cache) == 60
Expand Down Expand Up @@ -100,7 +101,7 @@ def test_set_with_ttl_hashable(policy):
cache = Cache(policy, 500)
foos = [Foo(i) for i in range(30)]
for i in range(30):
cache.set(foos[i], foos[i], timedelta(seconds=i))
cache.set(foos[i], foos[i], timedelta(seconds=i + 1))
assert len(cache) == 30
assert cache.key_gen.len() == 30
current = 30
Expand Down
2 changes: 1 addition & 1 deletion tests/test_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
from unittest.mock import Mock

import pytest

from bounded_zipf import Zipf

from theine import Cache, Memoize


Expand Down
7 changes: 4 additions & 3 deletions theine/adapters/django.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import time
from datetime import timedelta
from threading import Lock
from typing import DefaultDict, Optional, cast
from typing import Optional, cast

from django.core.cache.backends.base import DEFAULT_TIMEOUT, BaseCache

Expand All @@ -12,7 +11,9 @@
class Cache(BaseCache):
def __init__(self, name, params):
super().__init__(params)
self.cache = Theine("tlfu", self._max_entries)
options = params.get("OPTIONS", {})
policy = options.get("POLICY", "tlfu")
self.cache = Theine(policy, self._max_entries)

def _timeout_seconds(self, timeout) -> Optional[float]:
if timeout == DEFAULT_TIMEOUT:
Expand Down
2 changes: 2 additions & 0 deletions theine/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class InvalidTTL(Exception):
pass
67 changes: 30 additions & 37 deletions theine/thenie.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,13 @@
from datetime import timedelta
from functools import _make_key, update_wrapper
from threading import Event, Thread
from typing import (
Any,
Callable,
Dict,
Hashable,
List,
Optional,
Tuple,
TypeVar,
Union,
cast,
Type,
)


from theine_core import LruCore, TlfuCore, ClockProCore
from typing import (Any, Callable, Dict, Hashable, List, Optional, Tuple, Type,
TypeVar, Union, cast)

from theine_core import ClockProCore, LruCore, TlfuCore
from typing_extensions import ParamSpec, Protocol

from theine.exceptions import InvalidTTL

sentinel = object()

Expand Down Expand Up @@ -60,7 +49,7 @@ class Core(Protocol):
def __init__(self, size: int):
...

def set(self, key: str, expire: int) -> Tuple[int, Optional[int], Optional[str]]:
def set(self, key: str, ttl: int) -> Tuple[int, Optional[int], Optional[str]]:
...

def remove(self, key: str) -> Optional[int]:
Expand All @@ -69,7 +58,7 @@ def remove(self, key: str) -> Optional[int]:
def access(self, key: str) -> Optional[int]:
...

def advance(self, now: int, cache: List, sentinel: Any, kh: Dict, hk: Dict):
def advance(self, cache: List, sentinel: Any, kh: Dict, hk: Dict):
...

def clear(self):
Expand All @@ -84,7 +73,7 @@ def __init__(self, size: int):
...

def set(
self, key: str, expire: int
self, key: str, ttl: int
) -> Tuple[int, Optional[int], Optional[int], Optional[str]]:
...

Expand All @@ -94,7 +83,7 @@ def remove(self, key: str) -> Optional[int]:
def access(self, key: str) -> Optional[int]:
...

def advance(self, now: int, cache: List, sentinel: Any, kh: Dict, hk: Dict):
def advance(self, cache: List, sentinel: Any, kh: Dict, hk: Dict):
...

def clear(self):
Expand Down Expand Up @@ -314,11 +303,13 @@ def _access(self, key: Hashable, ttl: Optional[timedelta] = None):
else:
key_str = self.key_gen(key)

expire = None
ttl_ns = None
if ttl is not None:
now = time.time()
expire = now + max(ttl.total_seconds(), 1.0)
self.core.set(key_str, int(expire * 1e9) if expire is not None else 0)
seconds = ttl.total_seconds()
if seconds == 0:
raise Exception("ttl must be positive")
ttl_ns = int(seconds * 1e9)
self.core.set(key_str, ttl_ns or 0)

def set(
self, key: Hashable, value: Any, ttl: Optional[timedelta] = None
Expand All @@ -339,13 +330,14 @@ def set(
else:
key_str = self.key_gen(key)

expire = None
ttl_ns = None
if ttl is not None:
now = time.time()
expire = now + max(ttl.total_seconds(), 1.0)
index, evicted_index, evicted_key = self.core.set(
key_str, int(expire * 1e9) if expire is not None else 0
)
seconds = ttl.total_seconds()
if seconds <= 0:
raise InvalidTTL("ttl must be positive")
ttl_ns = int(seconds * 1e9)
# 0 means no ttl
index, evicted_index, evicted_key = self.core.set(key_str, ttl_ns or 0)
self._cache[index] = value
if evicted_index is not None:
self._cache[evicted_index] = sentinel
Expand Down Expand Up @@ -374,12 +366,15 @@ def _set_clockpro(
else:
key_str = self.key_gen(key)

expire = None
ttl_ns = None
if ttl is not None:
now = time.time()
expire = now + max(ttl.total_seconds(), 1.0)
# min res 1 second
seconds = ttl.total_seconds()
if seconds <= 0:
raise InvalidTTL("ttl must be positive")
ttl_ns = int(seconds * 1e9)
index, test_index, evicted_index, evicted_key = self.core.set(
key_str, int(expire * 1e9) if expire is not None else 0
key_str, ttl_ns or 0
)
self._cache[index] = value
if test_index is not None:
Expand Down Expand Up @@ -417,9 +412,7 @@ def maintenance(self):
Remove expired keys.
"""
while True:
self.core.advance(
time.time_ns(), self._cache, sentinel, self.key_gen.kh, self.key_gen.hk
)
self.core.advance(self._cache, sentinel, self.key_gen.kh, self.key_gen.hk)
time.sleep(0.5)

def clear(self):
Expand Down

0 comments on commit abc468f

Please sign in to comment.