@@ -15,6 +15,10 @@ def __init__(self, db, user, password, authdb, max_lag_secs):
1515 self .authdb = authdb
1616 self .max_lag_secs = max_lag_secs
1717
18+ self .rs_status = None
19+ self .primary = None
20+ self .secondary = None
21+
1822 # Get a DB connection
1923 try :
2024 if self .db .__class__ .__name__ == "DB" :
@@ -28,9 +32,11 @@ def __init__(self, db, user, password, authdb, max_lag_secs):
2832 def close (self ):
2933 pass
3034
31- def get_rs_status (self ):
35+ def get_rs_status (self , force = False ):
3236 try :
33- return self .db .admin_command ('replSetGetStatus' )
37+ if force or not self .rs_status :
38+ self .rs_status = self .db .admin_command ('replSetGetStatus' )
39+ return self .rs_status
3440 except Exception , e :
3541 raise Exception , "Error getting replica set status! Error: %s" % e , None
3642
@@ -44,16 +50,12 @@ def get_rs_config(self):
4450 except Exception , e :
4551 raise Exception , "Error getting replica set config! Error: %s" % e , None
4652
47- def find_secondary (self ):
48- rs_status = self .get_rs_status ()
49- rs_config = self .get_rs_config ()
50- rs_name = rs_status ['set' ]
51- quorum_count = ceil (len (rs_status ['members' ]) / 2.0 )
52-
53- primary = None
53+ def find_primary (self ):
54+ rs_status = self .get_rs_status ()
55+ rs_name = rs_status ['set' ]
5456 for member in rs_status ['members' ]:
5557 if member ['stateStr' ] == 'PRIMARY' and member ['health' ] > 0 :
56- primary = {
58+ self . primary = {
5759 'host' : member ['name' ],
5860 'optime' : member ['optimeDate' ]
5961 }
@@ -65,11 +67,18 @@ def find_secondary(self):
6567 member ['name' ],
6668 str (optime )
6769 ))
68- if primary is None :
70+ if self . primary is None :
6971 logging .fatal ("Unable to locate a PRIMARY member for replset %s, giving up" % rs_name )
7072 raise Exception , "Unable to locate a PRIMARY member for replset %s, giving up" % rs_name , None
71-
72- secondary = None
73+ return self .primary
74+
75+ def find_secondary (self ):
76+ rs_status = self .get_rs_status ()
77+ rs_config = self .get_rs_config ()
78+ rs_primary = self .find_primary ()
79+ rs_name = rs_status ['set' ]
80+ quorum_count = ceil (len (rs_status ['members' ]) / 2.0 )
81+
7382 for member in rs_status ['members' ]:
7483 if member ['stateStr' ] == 'SECONDARY' and member ['health' ] > 0 :
7584 score = self .max_lag_secs * 10
@@ -88,13 +97,13 @@ def find_secondary(self):
8897 score = score - member_config ['priority' ]
8998 break
9099
91- rep_lag = (mktime (primary [ 'optime' ] .timetuple ()) - mktime (member ['optimeDate' ].timetuple ()))
100+ rep_lag = (mktime (self . primary_optime () .timetuple ()) - mktime (member ['optimeDate' ].timetuple ()))
92101 score = ceil ((score - rep_lag ) * score_scale )
93102 if rep_lag < self .max_lag_secs :
94- if secondary is None or score > secondary ['score' ]:
95- secondary = {
103+ if self . secondary is None or score > self . secondary ['score' ]:
104+ self . secondary = {
96105 'replSet' : rs_name ,
97- 'count' : 1 if secondary is None else secondary ['count' ] + 1 ,
106+ 'count' : 1 if self . secondary is None else self . secondary ['count' ] + 1 ,
98107 'host' : member ['name' ],
99108 'optime' : member ['optimeDate' ],
100109 'score' : score
@@ -108,16 +117,22 @@ def find_secondary(self):
108117 log_data ['optime' ] = member ['optime' ]['ts' ]
109118 log_data ['score' ] = int (score )
110119 logging .info ("%s: %s" % (log_msg , str (log_data )))
111- if secondary is None or (secondary ['count' ] + 1 ) < quorum_count :
120+ if self . secondary is None or (self . secondary ['count' ] + 1 ) < quorum_count :
112121 logging .fatal ("Not enough secondaries in replset %s to take backup! Num replset members: %i, required quorum: %i" % (
113122 rs_name ,
114- secondary ['count' ] + 1 ,
123+ self . secondary ['count' ] + 1 ,
115124 quorum_count
116125 ))
117126 raise Exception , "Not enough secondaries in replset %s to safely take backup!" % rs_name , None
118127
119- logging .info ("Choosing SECONDARY %s for replica set %s (score: %i)" % (secondary ['host' ], rs_name , secondary ['score' ]))
120- return secondary
128+ logging .info ("Choosing SECONDARY %s for replica set %s (score: %i)" % (self .secondary ['host' ], rs_name , self .secondary ['score' ]))
129+ return self .secondary
130+
131+ def primary_optime (self ):
132+ rs_status = self .get_rs_status ()
133+ rs_primary = self .find_primary ()
134+ if 'optime' in rs_primary :
135+ return rs_primary ['optime' ]
121136
122137
123138class ReplsetSharded :
0 commit comments