aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Ionite <[email protected]>2022-11-16 15:13:28 -0500
committerGravatar Ionite <[email protected]>2022-11-16 15:13:28 -0500
commit85e6a189db683d1ee7e93a76297ea141ec9bd9f0 (patch)
tree908aacd12e361863e9262b5ebc2b115150634ed4
parentAdd zlib compression (diff)
Refactor to use individual tmpfs
-rw-r--r--snekbox/memfs.py49
1 files changed, 29 insertions, 20 deletions
diff --git a/snekbox/memfs.py b/snekbox/memfs.py
index 2eb83d2..e09cee7 100644
--- a/snekbox/memfs.py
+++ b/snekbox/memfs.py
@@ -5,7 +5,6 @@ import logging
import subprocess
from collections.abc import Generator
from contextlib import contextmanager
-from functools import cache
from pathlib import Path
from shutil import rmtree
from threading import BoundedSemaphore
@@ -15,33 +14,44 @@ from uuid import uuid4
from snekbox.snekio import FileAttachment
-# Size of the memory filesystem
-MEMFS_SIZE = "2G"
-# Maximum number of files attachments will be scanned for
-MAX_FILES = 6
-# Maximum size of a file attachment (64 MB)
-MAX_FILE_SIZE = 64 * 1024 * 1024
-
log = logging.getLogger(__name__)
-@cache
-def mem_tempdir() -> Path:
- """Return the snekbox namespace temporary directory."""
- tmp = Path("/snekbox/memfs")
+def mount_tmpfs(name: str) -> Path:
+ """Create and mount a tmpfs directory."""
+ tmp = Path("/snekbox/memfs", name)
if not tmp.exists() or not tmp.is_dir():
- # Create `memfs` and mount it as a tmpfs
+ # Create the directory
tmp.mkdir(parents=True, exist_ok=True)
tmp.chmod(0o777)
+ # Mount the tmpfs
subprocess.check_call(
- ["mount", "-t", "tmpfs", "-o", f"size={MEMFS_SIZE}", "tmpfs", str(tmp)]
+ ["mount", "-t", "tmpfs", "-o", f"size={MemFSOptions.MEMFS_SIZE}", "tmpfs", str(tmp)]
)
# Execute only access for other users
tmp.chmod(0o711)
-
return tmp
+def unmount_tmpfs(name: str) -> None:
+ """Unmount and remove a tmpfs directory."""
+ tmp = Path("/snekbox/memfs", name)
+ if tmp.exists() and tmp.is_dir():
+ subprocess.check_call(["umount", str(tmp)])
+ rmtree(tmp, ignore_errors=True)
+
+
+class MemFSOptions:
+ """Options for memory file system."""
+
+ # Size of the memory filesystem (per instance)
+ MEMFS_SIZE = "32M"
+ # Maximum number of files attachments will be scanned for
+ MAX_FILES = 2
+ # Maximum size of a file attachment (32 MB)
+ MAX_FILE_SIZE = 32 * 1024 * 1024
+
+
class MemoryTempDir:
"""A temporary directory using tmpfs."""
@@ -67,8 +77,7 @@ class MemoryTempDir:
for _ in range(10):
name = str(uuid4())
if name not in self.assigned_names:
- self.path = Path(mem_tempdir(), name)
- self.path.mkdir()
+ self.path = mount_tmpfs(name)
self.path.chmod(0o555)
# Create a home folder
home = self.path / "home"
@@ -97,16 +106,16 @@ class MemoryTempDir:
def attachments(self) -> Generator[FileAttachment, None, None]:
"""Return a list of attachments in the tempdir."""
# Look for any file starting with `output`
- for file in self.path.glob("output*"):
+ for file in self.home.glob("output*"):
if file.is_file():
- yield FileAttachment.from_path(file, MAX_FILE_SIZE)
+ yield FileAttachment.from_path(file, MemFSOptions.MAX_FILE_SIZE)
def cleanup(self) -> None:
"""Remove files in temp dir, releases name."""
if self.path is None:
return
# Remove the path folder
- rmtree(self.path, ignore_errors=True)
+ unmount_tmpfs(self.name)
if not self.path.exists():
with self.assignment_lock: