Skip to content

Commit 5b0cc20

Browse files
committed
Improve buffer serialization performance by performing bulk counter lookup
1 parent 3ab3267 commit 5b0cc20

2 files changed

Lines changed: 34 additions & 0 deletions

File tree

morango/api/serializers.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from collections import defaultdict
2+
13
from rest_framework import exceptions
24
from rest_framework import serializers
35
from rest_framework.fields import ReadOnlyField
@@ -158,11 +160,38 @@ class Meta:
158160
read_only_fields = fields
159161

160162

163+
class BufferListSerializer(serializers.ListSerializer):
164+
def to_representation(self, data):
165+
buffers = list(data)
166+
if buffers:
167+
rmcb_map = defaultdict(list)
168+
transfer_session_ids = {b.transfer_session_id for b in buffers}
169+
# Morango implementation will only ever call this for one transfer session ID at a time,
170+
# but a loop makes the code straightforward regardless and limits the quantity of
171+
# SQLite variables in use
172+
for transfer_session_id in transfer_session_ids:
173+
# bulk-fetch all RMCB records needed for this batch of buffers in a
174+
# single query, then cache the relevant subset on each buffer, instead
175+
# of letting each buffer's nested rmcb_list serializer issue its own query
176+
rmcb_queryset = RecordMaxCounterBuffer.objects.filter(
177+
transfer_session_id=transfer_session_id,
178+
model_uuid__in={b.model_uuid for b in buffers},
179+
)
180+
for rmcb in rmcb_queryset:
181+
rmcb_map[(transfer_session_id, rmcb.model_uuid)].append(rmcb)
182+
for buffer in buffers:
183+
buffer._rmcb_list = rmcb_map[
184+
(buffer.transfer_session_id, buffer.model_uuid)
185+
]
186+
return super(BufferListSerializer, self).to_representation(buffers)
187+
188+
161189
class BufferSerializer(serializers.ModelSerializer):
162190
rmcb_list = RecordMaxCounterBufferSerializer(many=True)
163191

164192
class Meta:
165193
model = Buffer
194+
list_serializer_class = BufferListSerializer
166195
fields = (
167196
"serialized",
168197
"deleted",

morango/models/core.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,11 @@ class Meta:
553553
unique_together = ("transfer_session", "model_uuid")
554554

555555
def rmcb_list(self):
556+
# allow callers (e.g. BufferListSerializer) to batch-fetch RMCB records
557+
# for many buffers at once and cache them here, to avoid an N+1 query
558+
# pattern when serializing a large number of buffers
559+
if hasattr(self, "_rmcb_list"):
560+
return self._rmcb_list
556561
return RecordMaxCounterBuffer.objects.filter(
557562
model_uuid=self.model_uuid, transfer_session_id=self.transfer_session_id
558563
)

0 commit comments

Comments
 (0)