Skip to content

Commit 0d9a164

Browse files
authored
Merge pull request #8276 from chrisburr/feat/zstandard-sandbox-support
feat: add zstandard compression support for sandbox files
2 parents 09fdfae + ab14db6 commit 0d9a164

File tree

2 files changed

+26
-1
lines changed

2 files changed

+26
-1
lines changed

setup.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ install_requires =
5656
Authlib >=1.0.0.a2
5757
pyjwt
5858
dominate
59+
zstandard
5960
zip_safe = False
6061
include_package_data = True
6162

src/DIRAC/WorkloadManagementSystem/Client/SandboxStoreClient.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
""" Client for the SandboxStore.
22
Will connect to the WorkloadManagement/SandboxStore service.
33
"""
4+
from __future__ import annotations
45

56
import hashlib
67
import os
78
import re
89
import tarfile
910
import tempfile
11+
from contextlib import contextmanager
1012
from io import BytesIO, StringIO
13+
from typing import Literal
14+
15+
import zstandard
1116

1217
from DIRAC import S_ERROR, S_OK, gLogger
1318
from DIRAC.ConfigurationSystem.Client.Helpers.Registry import getVOForGroup
@@ -18,6 +23,25 @@
1823
from DIRAC.Resources.Storage.StorageElement import StorageElement
1924

2025

26+
@contextmanager
27+
def ZstdCompatibleTarFile(tarFileName: os.PathLike, *, mode: Literal["r"] = "r"):
28+
"""Context manager to extend tarfile.open to support zstd compressed files.
29+
30+
This is only needed for Python <=3.13.
31+
"""
32+
with open(tarFileName, "rb") as f:
33+
magic = f.read(4)
34+
# Read magic bytes to determine compression format
35+
if magic.startswith(b"\x28\xb5\x2f\xfd"): # zstd magic number
36+
dctx = zstandard.ZstdDecompressor()
37+
with dctx.stream_reader(f) as decompressor:
38+
with tarfile.open(fileobj=decompressor, mode=f"{mode}|") as tf:
39+
yield tf
40+
else:
41+
with tarfile.open(name=tarFileName, mode=mode) as tf:
42+
yield tf
43+
44+
2145
class SandboxStoreClient:
2246
__validSandboxTypes = ("Input", "Output")
2347

@@ -192,7 +216,7 @@ def downloadSandbox(self, sbLocation, destinationDir="", inMemory=False, unpack=
192216

193217
try:
194218
sandboxSize = 0
195-
with tarfile.open(name=tarFileName, mode="r") as tf:
219+
with ZstdCompatibleTarFile(tarFileName, mode="r") as tf:
196220
for tarinfo in tf:
197221
tf.extract(tarinfo, path=destinationDir)
198222
sandboxSize += tarinfo.size

0 commit comments

Comments
 (0)