optimize views calculation

This commit is contained in:
knst-kotov 2021-12-15 15:01:22 +03:00
parent a98d5f6ee6
commit e2c8ceedbf

View File

@ -85,8 +85,9 @@ class ShoutViewByDay(Base):
class ShoutViewStorage: class ShoutViewStorage:
views = [] view_by_shout = {}
this_day_views = {} this_day_views = {}
to_flush = []
period = 30*60 #sec period = 30*60 #sec
@ -95,43 +96,55 @@ class ShoutViewStorage:
@staticmethod @staticmethod
def init(session): def init(session):
self = ShoutViewStorage self = ShoutViewStorage
self.views = session.query(ShoutViewByDay).all() views = session.query(ShoutViewByDay).all()
for view in self.views: for view in views:
shout_slug = view.shout shout = view.shout
if not shout_slug in self.this_day_views: value = view.value
self.this_day_views[shout_slug] = view old_value = self.view_by_shout.get(shout, 0)
this_day_view = self.this_day_views[shout_slug] self.view_by_shout[shout] = old_value + value;
if not shout in self.this_day_views:
self.this_day_views[shout] = view
this_day_view = self.this_day_views[shout]
if this_day_view.day < view.day: if this_day_view.day < view.day:
self.this_day_views[shout_slug] = view self.this_day_views[shout] = view
@staticmethod @staticmethod
async def get_view(shout_slug): async def get_view(shout_slug):
async with ShoutViewStorage.lock: self = ShoutViewStorage
shout_views = list(filter(lambda x: x.shout == shout_slug, ShoutViewStorage.views)) async with self.lock:
return reduce((lambda x, y: x + y.value), shout_views, 0) return self.view_by_shout.get(shout_slug, 0)
@staticmethod @staticmethod
async def inc_view(shout_slug): async def inc_view(shout_slug):
self = ShoutViewStorage self = ShoutViewStorage
async with ShoutViewStorage.lock: async with self.lock:
this_day_view = self.this_day_views.get(shout_slug) this_day_view = self.this_day_views.get(shout_slug)
day_start = datetime.now().replace(hour = 0, minute = 0, second = 0) day_start = datetime.now().replace(hour = 0, minute = 0, second = 0)
if not this_day_view or this_day_view.day < day_start: if not this_day_view or this_day_view.day < day_start:
if this_day_view and getattr(this_day_view, "modified", False):
self.to_flush.append(this_day_view)
this_day_view = ShoutViewByDay.create(shout = shout_slug, value = 1) this_day_view = ShoutViewByDay.create(shout = shout_slug, value = 1)
self.this_day_views[shout_slug] = this_day_view self.this_day_views[shout_slug] = this_day_view
self.views.append(this_day_view)
else: else:
this_day_view.value = this_day_view.value + 1 this_day_view.value = this_day_view.value + 1
this_day_view.modified = True
this_day_view.modified = True
old_value = self.view_by_shout.get(shout_slug, 0)
self.view_by_shout[shout_slug] = old_value + 1;
@staticmethod @staticmethod
async def flush_changes(session): async def flush_changes(session):
async with ShoutViewStorage.lock: self = ShoutViewStorage
for view in ShoutViewStorage.this_day_views.values(): async with self.lock:
for view in self.this_day_views.values():
if getattr(view, "modified", False): if getattr(view, "modified", False):
session.add(view) session.add(view)
flag_modified(view, "value") flag_modified(view, "value")
view.modified = False view.modified = False
for view in self.to_flush:
session.add(view)
self.to_flush.clear()
session.commit() session.commit()
@staticmethod @staticmethod
@ -150,6 +163,7 @@ class TopicStat:
shouts_by_topic = {} shouts_by_topic = {}
authors_by_topic = {} authors_by_topic = {}
subs_by_topic = {} subs_by_topic = {}
views_by_topic = {}
lock = asyncio.Lock() lock = asyncio.Lock()
period = 30*60 #sec period = 30*60 #sec
@ -172,6 +186,9 @@ class TopicStat:
else: else:
self.authors_by_topic[topic] = set(authors) self.authors_by_topic[topic] = set(authors)
old_views = self.views_by_topic.get(topic, 0)
self.views_by_topic[topic] = old_views + await ShoutViewStorage.get_view(shout)
subs = session.query(TopicSubscription) subs = session.query(TopicSubscription)
for sub in subs: for sub in subs:
topic = sub.topic topic = sub.topic
@ -192,20 +209,16 @@ class TopicStat:
async with self.lock: async with self.lock:
shouts = self.shouts_by_topic.get(topic, []) shouts = self.shouts_by_topic.get(topic, [])
subs = self.subs_by_topic.get(topic, []) subs = self.subs_by_topic.get(topic, [])
authors = self.authors_by_topic.get(topic, set()) authors = self.authors_by_topic.get(topic, [])
stat = { views = self.views_by_topic.get(topic, 0)
return {
"shouts" : len(shouts), "shouts" : len(shouts),
"authors" : len(authors), "authors" : len(authors),
"subscriptions" : len(subs) "subscriptions" : len(subs),
"views" : views
} }
views = 0
for shout in shouts:
views += await ShoutViewStorage.get_view(shout)
stat["views"] = views
return stat
@staticmethod @staticmethod
async def worker(): async def worker():
self = TopicStat self = TopicStat