| 
8 | 8 | from django.db import models  | 
9 | 9 | from django.utils import timezone  | 
10 | 10 | 
 
  | 
 | 11 | +from thunderstore.cache.utils import get_cache  | 
11 | 12 | from thunderstore.core.mixins import S3FileMixin  | 
12 | 13 | 
 
  | 
 | 14 | +cache = get_cache("legacy")  | 
 | 15 | +CACHE_LOCK_TIMEOUT = 30  | 
 | 16 | + | 
13 | 17 | 
 
  | 
14 | 18 | def get_schema_file_path(_, filename: str) -> str:  | 
15 | 19 |     return f"schema/sha256/{filename}"  | 
@@ -39,27 +43,30 @@ def get_or_create(cls, content: bytes) -> "SchemaFile":  | 
39 | 43 |         hash.update(content)  | 
40 | 44 |         checksum = hash.hexdigest()  | 
41 | 45 | 
 
  | 
42 |  | -        if existing := cls.objects.filter(checksum_sha256=checksum).first():  | 
43 |  | -            return existing  | 
 | 46 | +        lock_key = f"lock.schemafile.{checksum}"  | 
 | 47 | +        with cache.lock(lock_key, timeout=CACHE_LOCK_TIMEOUT, blocking_timeout=None):  | 
 | 48 | +            if existing := cls.objects.filter(checksum_sha256=checksum).first():  | 
 | 49 | +                return existing  | 
 | 50 | + | 
 | 51 | +            gzipped = io.BytesIO()  | 
 | 52 | +            with gzip.GzipFile(fileobj=gzipped, mode="wb") as f:  | 
 | 53 | +                f.write(content)  | 
 | 54 | +            timestamp = timezone.now()  | 
44 | 55 | 
 
  | 
45 |  | -        gzipped = io.BytesIO()  | 
46 |  | -        with gzip.GzipFile(fileobj=gzipped, mode="wb") as f:  | 
47 |  | -            f.write(content)  | 
48 |  | -        timestamp = timezone.now()  | 
 | 56 | +            file = ContentFile(  | 
 | 57 | +                # TODO: This is immediately passed to BytesIO again, meaning  | 
 | 58 | +                #       we're just wasting memory. Find a way to pass this to  | 
 | 59 | +                #       the Django model without the inefficiency.  | 
 | 60 | +                gzipped.getvalue(),  | 
 | 61 | +                name=f"{checksum}.json.gz",  | 
 | 62 | +            )  | 
49 | 63 | 
 
  | 
50 |  | -        file = ContentFile(  | 
51 |  | -            # TODO: This is immediately passed to BytesIO again, meaning  | 
52 |  | -            #       we're just wasting memory. Find a way to pass this to  | 
53 |  | -            #       the Django model without the inefficiency.  | 
54 |  | -            gzipped.getvalue(),  | 
55 |  | -            name=f"{checksum}.json.gz",  | 
56 |  | -        )  | 
57 |  | -        return cls.objects.create(  | 
58 |  | -            data=file,  | 
59 |  | -            content_type="application/json",  | 
60 |  | -            content_encoding="gzip",  | 
61 |  | -            last_modified=timestamp,  | 
62 |  | -            checksum_sha256=checksum,  | 
63 |  | -            file_size=len(content),  | 
64 |  | -            gzip_size=file.size,  | 
65 |  | -        )  | 
 | 64 | +            return cls.objects.create(  | 
 | 65 | +                data=file,  | 
 | 66 | +                content_type="application/json",  | 
 | 67 | +                content_encoding="gzip",  | 
 | 68 | +                last_modified=timestamp,  | 
 | 69 | +                checksum_sha256=checksum,  | 
 | 70 | +                file_size=len(content),  | 
 | 71 | +                gzip_size=file.size,  | 
 | 72 | +            )  | 
0 commit comments