Skip to content

Add persistent caching support for index classes - #88

Open
mateo-velez wants to merge 6 commits into
EpicWink:masterfrom
mateo-velez:feature/persistent-index
Open

Add persistent caching support for index classes#88
mateo-velez wants to merge 6 commits into
EpicWink:masterfrom
mateo-velez:feature/persistent-index

Conversation

@mateo-velez

Copy link
Copy Markdown

Issue: #87

- Add sqlitedict dependency to pyproject.toml and update app.requirements.txt
- Replace in-memory _IndexCache dictionaries with SqliteDict
@mateo-velez
mateo-velez force-pushed the feature/persistent-index branch from b6e10b3 to c9b3adb Compare July 3, 2026 07:04
@mateo-velez mateo-velez changed the title Add persistence to index caching Add persistent caching support for index classes Jul 3, 2026

@EpicWink EpicWink left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment in the issue

Comment thread app.requirements.txt

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you removing the hashes? Don't bother updating the Docker image app dependency pins here, I'll do it in a separate commit.

Comment thread pyproject.toml Outdated
"jinja2 ~= 3.0",
"lxml >= 4.8, < 7.0",
"requests ~= 2.27",
"sqlitedict >= 2.0, < 3.0",

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"sqlitedict >= 2.0, < 3.0",

Don't introduce a third-party dependency; use sqlite3 instead

Comment thread src/proxpi/_cache.py Outdated
return
self._index_t = None
self._index = {}
with self._index_lock:

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't remove the no-op for concurrent calls to invalidate_list

Comment thread src/proxpi/_cache.py Outdated
logger.info(f"Project '{name}' files already undergoing update")
return
self._packages.pop(package_name, None)
with self._package_locks[name]:

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't remove the no-op for concurrent calls to invalidate_project

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. However, it's worth pointing out that the method may return as if the invalidation has completed, while another concurrent call is still in progress.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is true. The intention is to not immediately invalidate after the index is updated

Comment thread src/proxpi/_cache.py Outdated
)
self._index_lock = threading.Lock()
self._index_metadata = sqlitedict.SqliteDict(
self.cache_file,

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cache_file should be an input argument (and environment variable). If not set, the original in-memory caching should be used instead

- Revert app.requirements.txt and pyproject.toml
- Add no-op to invalidation methods for the index cache class
- Add optional env var PROXPI_INDEX_CACHE_DIR to enable persistent index caching
@mateo-velez
mateo-velez force-pushed the feature/persistent-index branch from b64659a to dc40817 Compare July 10, 2026 08:59
@mateo-velez

Copy link
Copy Markdown
Author

I'm considering adding some unit testing for that specific new class, if I get the green flag ofc.

Comment thread src/proxpi/_cache.py Outdated

- Keys are expected to be strings.
- Thread-safety must be handled by the caller.
"""

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"""
Heavily inspired by 'sqlitedict': https://github.com/piskvorky/sqlitedict
"""

Reference source

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it.

Comment thread src/proxpi/_cache.py Outdated
Comment on lines +508 to +519
def __init__(self, path: str):
self.conn = sqlite3.connect(path, check_same_thread=False)
self.conn.execute("PRAGMA synchronous = NORMAL;")
self.conn.execute("PRAGMA journal_mode = WAL;")

self.table_name = "t"
self.encode = pickle.dumps
self.decode = pickle.loads

self.conn.execute(
f"CREATE TABLE IF NOT EXISTS {self.table_name} (key BLOB PRIMARY KEY, value BLOB)"
)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def __init__(self, path: str):
self.conn = sqlite3.connect(path, check_same_thread=False)
self.conn.execute("PRAGMA synchronous = NORMAL;")
self.conn.execute("PRAGMA journal_mode = WAL;")
self.table_name = "t"
self.encode = pickle.dumps
self.decode = pickle.loads
self.conn.execute(
f"CREATE TABLE IF NOT EXISTS {self.table_name} (key BLOB PRIMARY KEY, value BLOB)"
)
def __init__(self, conn: sqlite3.Connection, table_name: str) -> None:
self.conn = conn
self.table_name = table_name
self.encode = pickle.dumps
self.decode = pickle.loads
def ensure_initialised(self) -> None:
self.conn.execute(
f"CREATE TABLE IF NOT EXISTS {self.table_name} (key BLOB PRIMARY KEY, value BLOB)"
)
  • I think it's better to have one database (file), with multiple tables
  • Don't run complex code inside __init__ (makes unit testing much simpler)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • One file per table allow us to concurrently perform modification of package and index tables. Although, one file is indeed simpler and cleaner.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's unlikely that we have modification of package and index caches at the same time, to the point where I prefer the simplicity of the code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants