Skip to content

Commit 93460c9

Browse files
committed
feat: Calculate and display total problem file storage by summing all attached files instead of just test data.
1 parent 282bd42 commit 93460c9

File tree

4 files changed

+46
-28
lines changed

4 files changed

+46
-28
lines changed

judge/management/commands/backfill_problem_data_size.py

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,33 +19,51 @@ def handle(self, *args, **options):
1919
if dry_run:
2020
self.stdout.write(self.style.WARNING('DRY RUN MODE - No changes will be saved'))
2121

22-
problem_data_list = ProblemData.objects.select_related('problem').all()
23-
total_count = problem_data_list.count()
22+
from django.conf import settings
23+
import os
24+
25+
problem_data_list = ProblemData.objects.all().iterator(chunk_size=5000)
26+
total_count = ProblemData.objects.count()
2427
updated_count = 0
28+
batch_size = 1000
29+
batch = []
30+
root = settings.DMOJ_PROBLEM_DATA_ROOT
2531

2632
self.stdout.write(f'Processing {total_count} problems...\n')
2733

2834
for problem_data in problem_data_list:
29-
problem_code = problem_data.problem.code
3035
old_zipfile_size = problem_data.zipfile_size
36+
total_size = 0
3137

32-
# Calculate new sizes
33-
problem_data.update_zipfile_size()
38+
# Calculate new sizes directly via OS to bypass Storage abstractions overhead
39+
for field in ['zipfile', 'generator', 'custom_checker', 'custom_grader', 'custom_header']:
40+
val = getattr(problem_data, field)
41+
if val and val.name:
42+
path = os.path.join(root, val.name)
43+
try:
44+
total_size += os.path.getsize(path)
45+
except (OSError, FileNotFoundError):
46+
pass
3447

35-
new_zipfile_size = problem_data.zipfile_size
48+
new_zipfile_size = total_size
3649

3750
# Check if anything changed
3851
if old_zipfile_size != new_zipfile_size:
52+
problem_data.zipfile_size = new_zipfile_size
53+
batch.append(problem_data)
3954
updated_count += 1
4055

4156
self.stdout.write(
42-
f'Problem: {problem_code}\n'
43-
f' Test data: {self._format_size(old_zipfile_size)} -> {self._format_size(new_zipfile_size)}\n',
57+
f'Problem: {problem_data.problem_id}\n'
58+
f' Total Storage: {self._format_size(old_zipfile_size)} -> {self._format_size(new_zipfile_size)}\n',
4459
)
4560

46-
if not dry_run:
47-
# Use update_fields to avoid triggering save hooks again
48-
problem_data.save(update_fields=['zipfile_size'])
61+
if len(batch) >= batch_size and not dry_run:
62+
ProblemData.objects.bulk_update(batch, ['zipfile_size'])
63+
batch = []
64+
65+
if batch and not dry_run:
66+
ProblemData.objects.bulk_update(batch, ['zipfile_size'])
4967

5068
if dry_run:
5169
self.stdout.write(self.style.WARNING(f'\nDRY RUN: Would update {updated_count}/{total_count} problems'))

judge/models/problem_data.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -99,15 +99,15 @@ def has_yml(self):
9999
return problem_data_storage.exists('%s/init.yml' % self.problem.code)
100100

101101
def update_zipfile_size(self):
102-
"""Update the zipfile_size field based on the actual file size."""
103-
if self.zipfile:
104-
try:
105-
self.zipfile_size = self.zipfile.size
106-
except (OSError, IOError):
107-
# If file doesn't exist or can't be accessed, set size to 0
108-
self.zipfile_size = 0
109-
else:
110-
self.zipfile_size = 0
102+
"""Update the zipfile_size field based on the actual size of all attached files."""
103+
total_size = 0
104+
for field in [self.zipfile, self.generator, self.custom_checker, self.custom_grader, self.custom_header]:
105+
if field:
106+
try:
107+
total_size += field.size
108+
except (OSError, IOError, ValueError):
109+
pass
110+
self.zipfile_size = total_size
111111

112112
def save(self, *args, **kwargs):
113113
# Update zipfile size before saving

judge/views/organization.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -789,25 +789,25 @@ def get_context_data(self, **kwargs):
789789
storage_totals = ProblemData.objects.filter(
790790
problem__organization=self.organization,
791791
).aggregate(
792-
test_data=Sum('zipfile_size'),
792+
total_storage=Sum('zipfile_size'),
793793
)
794794

795-
test_data_total = storage_totals['test_data'] or 0
795+
total_storage_used = storage_totals['total_storage'] or 0
796796

797797
cached_data = {
798-
'test_data': test_data_total,
798+
'total_storage': total_storage_used,
799799
}
800800

801801
cache_factory.set_cache(cached_data)
802802

803-
context['test_data_storage'] = cached_data['test_data']
803+
context['total_storage'] = cached_data.get('total_storage', cached_data.get('test_data', 0))
804804

805805
# Quota information
806806
org = self.organization
807807
context['max_storage'] = org.get_max_storage()
808808
context['max_problems'] = org.get_max_problems()
809809
context['problem_count'] = org.get_current_problem_count()
810-
context['storage_exceeded'] = context['test_data_storage'] > org.get_max_storage()
810+
context['storage_exceeded'] = context['total_storage'] > org.get_max_storage()
811811
context['problem_limit_reached'] = context['problem_count'] >= org.get_max_problems()
812812

813813
context.update(paginate_query_context(self.request))

templates/organization/storage.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
<h3>{{ _('Storage Summary') }}</h3>
3838
<div style="margin-left: 2em; color: #666;">
3939
<p style="margin: 0.25em 0;">
40-
{{ _('Test data:') }} {{ test_data_storage|filesizeformat }}
40+
{{ _('Total Storage:') }} {{ total_storage|filesizeformat }}
4141
/ {{ max_storage|filesizeformat }}
4242
</p>
4343
<p style="margin: 0.25em 0;">
@@ -47,7 +47,7 @@ <h3>{{ _('Storage Summary') }}</h3>
4747

4848
{% if storage_exceeded %}
4949
<div class="quota-warning">
50-
{{ _('Storage limit reached! Please delete some test data to free up space.') }}
50+
{{ _('Storage limit reached! Please delete some files or test data to free up space.') }}
5151
</div>
5252
{% endif %}
5353

@@ -63,7 +63,7 @@ <h3>{{ _('Storage Summary') }}</h3>
6363
<tr>
6464
<th>{{ _('Problem Code') }}</th>
6565
<th>{{ _('Problem Name') }}</th>
66-
<th>{{ _('Test Data') }}</th>
66+
<th>{{ _('Total Size') }}</th>
6767
</tr>
6868
</thead>
6969
<tbody>

0 commit comments

Comments
 (0)