From ffdfbed42c48a4b85c26f224f32003b8bda2ce78 Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Tue, 17 Apr 2018 19:02:10 +0200 Subject: [PATCH] [FIX] calendar: avoid memory overflow On a DB with thousands of events including recurring ones, fetching the complete list of events might lead to a memory overflow due to the prefetching of all virtual events. We reduce the memory footprint by handling no more than 50,000 records at a time and clearing the cache at each step. This limit is purely arbitrary, but seems to be a good compromise between performance and memory usage. opw-1832482 --- addons/calendar/models/calendar.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/addons/calendar/models/calendar.py b/addons/calendar/models/calendar.py index f105ea7095c..4d377e295d8 100644 --- a/addons/calendar/models/calendar.py +++ b/addons/calendar/models/calendar.py @@ -617,13 +617,21 @@ class Meeting(models.Model): event_date = event_date.astimezone(timezone) # transform "+hh:mm" timezone rset1 = rrule.rrulestr(str(self.rrule), dtstart=event_date, forceset=True, tzinfos={}) recurring_meetings = self.search([('recurrent_id', '=', self.id), '|', ('active', '=', False), ('active', '=', True)]) - for meeting in recurring_meetings: - recurring_date = fields.Datetime.from_string(meeting.recurrent_id_date) - if use_naive_datetime: - recurring_date = recurring_date.replace(tzinfo=None) - else: - recurring_date = todate(meeting.recurrent_id_date) - rset1.exdate(recurring_date) + + # We handle a maximum of 50,000 meetings at a time, and clear the cache at each step to + # control the memory usage. + invalidate = False + for meetings in self.env.cr.split_for_in_conditions(recurring_meetings, size=50000): + if invalidate: + self.invalidate_cache() + for meeting in meetings: + recurring_date = fields.Datetime.from_string(meeting.recurrent_id_date) + if use_naive_datetime: + recurring_date = recurring_date.replace(tzinfo=None) + else: + recurring_date = todate(meeting.recurrent_id_date) + rset1.exdate(recurring_date) + invalidate = True return [d.astimezone(pytz.UTC) if d.tzinfo else d for d in rset1] @api.multi