Skip to content

Commit 1cdbb5d

Browse files
author
tony.t.tseng
committed
Added a script for backfilling channel_count extra property.
Review URL: http://rietku.appspot.com/28001 git-svn-id: http://jaikuengine.googlecode.com/svn/trunk@93 6315f19a-1029-11de-a3bf-55d8bd1d7a4a
1 parent 2de4856 commit 1cdbb5d

File tree

1 file changed

+123
-0
lines changed

1 file changed

+123
-0
lines changed

bin/backfill_channel_count.py

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
#!/usr/bin/env python
2+
# Copyright 2009 Google Inc.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
import getpass
17+
import logging
18+
import os
19+
import optparse
20+
import sys
21+
22+
sys.path.append(".")
23+
sys.path.append("./vendor")
24+
25+
from appengine_django import InstallAppengineHelperForDjango
26+
InstallAppengineHelperForDjango()
27+
28+
from google.appengine.ext.remote_api import remote_api_stub
29+
from google.appengine.ext import db
30+
31+
from common import models
32+
from common import util
33+
34+
class ChannelCountBackfiller(object):
35+
"""Backfills the channel_count extra property for all users.
36+
37+
This script should be idempotent - running it again would merely overwrite the
38+
previous result.
39+
40+
Make sure to run it from the top jaikuengine directory. The following command
41+
would execute the script against a local testing instance:
42+
'./bin/backfill_channel_count.py -w 1 -s localhost:8080'
43+
"""
44+
45+
def __init__(self, do_write):
46+
self._do_write = do_write
47+
48+
def get_channel_count(self, actor_nick):
49+
"""Returns the number of channels the actor is a member of."""
50+
batch_size = 1000
51+
count = 0
52+
q = self.get_channel_relationship_query(actor_nick)
53+
memberships = q.fetch(batch_size)
54+
while memberships:
55+
count += len(memberships)
56+
q = self.get_channel_relationship_query(actor_nick)
57+
q.filter("__key__ >", memberships[-1].key())
58+
memberships = q.fetch(batch_size)
59+
60+
return count
61+
62+
def get_channel_relationship_query(self, actor_nick):
63+
q = models.Relation.all(keys_only=True)
64+
q.filter("relation =", "channelmember")
65+
q.filter("target =", actor_nick)
66+
q.order("__key__")
67+
return q
68+
69+
def get_actor_query(self):
70+
q = models.Actor.all()
71+
q.order("__key__")
72+
return q
73+
74+
def run(self, batch_size=100):
75+
"""Updates the channel_count extra property for users."""
76+
actor_refs = self.get_actor_query().fetch(batch_size)
77+
actors_processed = 0
78+
while actor_refs:
79+
to_put = []
80+
for actor_ref in actor_refs:
81+
if not util.is_channel_nick(actor_ref.nick):
82+
actor_ref.extra["channel_count"] \
83+
= self.get_channel_count(actor_ref.nick)
84+
to_put.append(actor_ref)
85+
if not self._do_write:
86+
logging.info("Would have set channel_count to %d for %s",
87+
actor_ref.extra["channel_count"],
88+
actor_ref.nick)
89+
90+
if to_put and self._do_write:
91+
db.put(to_put)
92+
actors_processed += len(actor_refs)
93+
logging.info("Processed %d actors...", actors_processed)
94+
q = self.get_actor_query()
95+
q.filter("__key__ >", actor_refs[-1].key())
96+
actor_refs = q.fetch(batch_size)
97+
98+
99+
def auth_function():
100+
return ("admin", getpass.getpass("Password:"))
101+
102+
def main():
103+
parser = optparse.OptionParser()
104+
parser.add_option("-b", "--actor_batch_size", dest="actor_batch_size",
105+
default=100,
106+
help="number of actors to fetch in a single query")
107+
parser.add_option("-w", "--write", dest="write", default=False,
108+
help="write results back to data store")
109+
parser.add_option("-a", "--app_id", dest="app_id",
110+
help="the app_id of your app, as declared in app.yaml")
111+
parser.add_option("-s", "--servername", dest="servername",
112+
help="the hostname your app is deployed on. Defaults to"
113+
"<app_id>.appspot.com")
114+
(options, args) = parser.parse_args()
115+
remote_api_stub.ConfigureRemoteDatastore(app_id=options.app_id,
116+
path='/remote_api',
117+
auth_func=auth_function,
118+
servername=options.servername)
119+
120+
ChannelCountBackfiller(options.write).run(int(options.actor_batch_size))
121+
122+
if __name__ == "__main__":
123+
main()

0 commit comments

Comments
 (0)