Merge branch 'master' of git://git.assembla.com/fpdb-sql

This commit is contained in:
Worros 2009-07-19 11:29:18 +08:00
commit e113a1e692
7 changed files with 322 additions and 92 deletions

View File

@ -64,32 +64,47 @@ class Database:
# Future values may also include: # Future values may also include:
# H=Hands (last n hands) # H=Hands (last n hands)
self.hud_hands = 1000 # Max number of hands from each player to use for hud stats self.hud_hands = 1000 # Max number of hands from each player to use for hud stats
self.hud_days = 90 # Max number of days from each player to use for hud stats self.hud_days = 30 # Max number of days from each player to use for hud stats
self.hud_session_gap = 30 # Gap (minutes) between hands that indicates a change of session self.hud_session_gap = 30 # Gap (minutes) between hands that indicates a change of session
# (hands every 2 mins for 1 hour = one session, if followed # (hands every 2 mins for 1 hour = one session, if followed
# by a 40 minute gap and then more hands on same table that is # by a 40 minute gap and then more hands on same table that is
# a new session) # a new session)
cur = self.connection.cursor() self.cursor = self.fdb.cursor
if self.fdb.wrongDbVersion == False: if self.fdb.wrongDbVersion == False:
# self.hand_1day_ago used to fetch stats for current session (i.e. if hud_style = 'S')
self.hand_1day_ago = 0 self.hand_1day_ago = 0
cur.execute(self.sql.query['get_hand_1day_ago']) self.cursor.execute(self.sql.query['get_hand_1day_ago'])
row = cur.fetchone() row = self.cursor.fetchone()
if row and row[0]: if row and row[0]:
self.hand_1day_ago = row[0] self.hand_1day_ago = row[0]
#print "hand 1day ago =", self.hand_1day_ago #print "hand 1day ago =", self.hand_1day_ago
# self.date_ndays_ago used if hud_style = 'T'
d = timedelta(days=self.hud_days) d = timedelta(days=self.hud_days)
now = datetime.utcnow() - d now = datetime.utcnow() - d
self.date_ndays_ago = "d%02d%02d%02d" % (now.year-2000, now.month, now.day) self.date_ndays_ago = "d%02d%02d%02d" % (now.year-2000, now.month, now.day)
self.hand_nhands_ago = 0 # todo # self.hand_nhands_ago is used for fetching stats for last n hands (hud_style = 'H')
#cur.execute(self.sql.query['get_table_name'], (hand_id, )) # This option not used yet
#row = cur.fetchone() self.hand_nhands_ago = 0
# should use aggregated version of query if appropriate
self.cursor.execute(self.sql.query['get_hand_nhands_ago'], (self.hud_hands,self.hud_hands))
row = self.cursor.fetchone()
if row and row[0]:
self.hand_nhands_ago = row[0]
print "hand n hands ago =", self.hand_nhands_ago
#self.cursor.execute(self.sql.query['get_table_name'], (hand_id, ))
#row = self.cursor.fetchone()
else: else:
print "Bailing on DB query, not sure it exists yet" print "Bailing on DB query, not sure it exists yet"
self.saveActions = False if self.import_options['saveActions'] == False else True self.saveActions = False if self.import_options['saveActions'] == False else True
# could be used by hud to change hud style
def set_hud_style(self, style):
self.hud_style = style
def do_connect(self, c): def do_connect(self, c):
self.fdb.do_connect(c) self.fdb.do_connect(c)

View File

@ -1064,6 +1064,7 @@ class FpdbSQLQueries:
<orderbyseats> <orderbyseats>
,case <position> when 'B' then 'B' ,case <position> when 'B' then 'B'
when 'S' then 'S' when 'S' then 'S'
when '0' then 'Y'
else 'Z'||<position> else 'Z'||<position>
end end
<orderbyhgameTypeId> <orderbyhgameTypeId>

View File

@ -154,31 +154,40 @@ class GuiAutoImport (threading.Thread):
# results to the same pipe. This means that self.path should be a a list of dirs # results to the same pipe. This means that self.path should be a a list of dirs
# to watch. # to watch.
if widget.get_active(): # toggled on if widget.get_active(): # toggled on
self.doAutoImportBool = True # - Does the lock acquisition need to be more sophisticated for multiple dirs?
widget.set_label(u' _Stop Autoimport ') # (see comment above about what to do if pipe already open)
if self.pipe_to_hud is None: # - Ideally we want to release the lock if the auto-import is killed by some
if os.name == 'nt': # kind of exception - is this possible?
command = "python HUD_main.py" + " " + self.settings['cl_options'] if self.settings['global_lock'].acquire(False): # returns false immediately if lock not acquired
bs = 0 # windows is not happy with line buffing here print "\nGlobal lock taken ..."
self.pipe_to_hud = subprocess.Popen(command, bufsize = bs, stdin = subprocess.PIPE, self.doAutoImportBool = True
universal_newlines=True) widget.set_label(u' _Stop Autoimport ')
else: if self.pipe_to_hud is None:
command = os.path.join(sys.path[0], 'HUD_main.py') if os.name == 'nt':
cl = [command, ] + string.split(self.settings['cl_options']) command = "python HUD_main.py" + " " + self.settings['cl_options']
self.pipe_to_hud = subprocess.Popen(cl, bufsize = 1, stdin = subprocess.PIPE, bs = 0 # windows is not happy with line buffing here
universal_newlines=True) self.pipe_to_hud = subprocess.Popen(command, bufsize = bs, stdin = subprocess.PIPE,
universal_newlines=True)
else:
command = os.path.join(sys.path[0], 'HUD_main.py')
cl = [command, ] + string.split(self.settings['cl_options'])
self.pipe_to_hud = subprocess.Popen(cl, bufsize = 1, stdin = subprocess.PIPE,
universal_newlines=True)
# Add directories to importer object. # Add directories to importer object.
for site in self.input_settings: for site in self.input_settings:
self.importer.addImportDirectory(self.input_settings[site][0], True, site, self.input_settings[site][1]) self.importer.addImportDirectory(self.input_settings[site][0], True, site, self.input_settings[site][1])
print "Adding import directories - Site: " + site + " dir: "+ str(self.input_settings[site][0]) print "Adding import directories - Site: " + site + " dir: "+ str(self.input_settings[site][0])
self.do_import() self.do_import()
interval=int(self.intervalEntry.get_text()) interval=int(self.intervalEntry.get_text())
gobject.timeout_add(interval*1000, self.do_import) gobject.timeout_add(interval*1000, self.do_import)
else:
print "auto-import aborted - global lock not available"
else: # toggled off else: # toggled off
self.settings['global_lock'].release()
self.doAutoImportBool = False # do_import will return this and stop the gobject callback timer self.doAutoImportBool = False # do_import will return this and stop the gobject callback timer
print "Stopping autoimport" print "Stopping autoimport - global lock released."
if self.pipe_to_hud.poll() is not None: if self.pipe_to_hud.poll() is not None:
print "HUD already terminated" print "HUD already terminated"
else: else:
@ -186,8 +195,6 @@ class GuiAutoImport (threading.Thread):
self.pipe_to_hud.communicate('\n') # waits for process to terminate self.pipe_to_hud.communicate('\n') # waits for process to terminate
self.pipe_to_hud = None self.pipe_to_hud = None
self.startButton.set_label(u' _Start Autoimport ') self.startButton.set_label(u' _Start Autoimport ')
#end def GuiAutoImport.startClicked #end def GuiAutoImport.startClicked

View File

@ -49,37 +49,47 @@ class GuiBulkImport():
self.importer.RunImportThreaded() self.importer.RunImportThreaded()
def load_clicked(self, widget, data=None): def load_clicked(self, widget, data=None):
# get the dir to import from the chooser # Does the lock acquisition need to be more sophisticated for multiple dirs?
self.inputFile = self.chooser.get_filename() # (see comment above about what to do if pipe already open)
if self.settings['global_lock'].acquire(False): # returns false immediately if lock not acquired
try:
print "\nGlobal lock taken ..."
# get the dir to import from the chooser
self.inputFile = self.chooser.get_filename()
# get the import settings from the gui and save in the importer # get the import settings from the gui and save in the importer
self.importer.setHandCount(int(self.spin_hands.get_text())) self.importer.setHandCount(int(self.spin_hands.get_text()))
self.importer.setMinPrint(int(self.spin_hands.get_text())) self.importer.setMinPrint(int(self.spin_hands.get_text()))
self.importer.setQuiet(self.chk_st_st.get_active()) self.importer.setQuiet(self.chk_st_st.get_active())
self.importer.setFailOnError(self.chk_fail.get_active()) self.importer.setFailOnError(self.chk_fail.get_active())
self.importer.setThreads(int(self.spin_threads.get_text())) self.importer.setThreads(int(self.spin_threads.get_text()))
self.importer.setHandsInDB(self.n_hands_in_db) self.importer.setHandsInDB(self.n_hands_in_db)
cb_model = self.cb_dropindexes.get_model() cb_model = self.cb_dropindexes.get_model()
cb_index = self.cb_dropindexes.get_active() cb_index = self.cb_dropindexes.get_active()
if cb_index: if cb_index:
self.importer.setDropIndexes(cb_model[cb_index][0]) self.importer.setDropIndexes(cb_model[cb_index][0])
else:
self.importer.setDropIndexes("auto")
sitename = self.cbfilter.get_model()[self.cbfilter.get_active()][0]
self.lab_info.set_text("Importing")
self.importer.addBulkImportImportFileOrDir(self.inputFile, site = sitename)
self.importer.setCallHud(False)
starttime = time()
(stored, dups, partial, errs, ttime) = self.importer.runImport()
ttime = time() - starttime
if ttime == 0:
ttime = 1
print 'GuiBulkImport.import_dir done: Stored: %d \tDuplicates: %d \tPartial: %d \tErrors: %d in %s seconds - %d/sec'\
% (stored, dups, partial, errs, ttime, stored / ttime)
self.importer.clearFileList()
self.lab_info.set_text("Import finished")
except:
pass
self.settings['global_lock'].release()
else: else:
self.importer.setDropIndexes("auto") print "bulk-import aborted - global lock not available"
sitename = self.cbfilter.get_model()[self.cbfilter.get_active()][0]
self.lab_info.set_text("Importing")
self.importer.addBulkImportImportFileOrDir(self.inputFile, site = sitename)
self.importer.setCallHud(False)
starttime = time()
(stored, dups, partial, errs, ttime) = self.importer.runImport()
ttime = time() - starttime
if ttime == 0:
ttime = 1
print 'GuiBulkImport.import_dir done: Stored: %d \tDuplicates: %d \tPartial: %d \tErrors: %d in %s seconds - %d/sec'\
% (stored, dups, partial, errs, ttime, stored / ttime)
self.importer.clearFileList()
self.lab_info.set_text("Import finished")
def get_vbox(self): def get_vbox(self):
"""returns the vbox of this thread""" """returns the vbox of this thread"""
@ -88,8 +98,7 @@ class GuiBulkImport():
def __init__(self, settings, config): def __init__(self, settings, config):
self.settings = settings self.settings = settings
self.config = config self.config = config
self.importer = fpdb_import.Importer(self, self.settings, self.importer = fpdb_import.Importer(self, self.settings, config)
config)
self.vbox = gtk.VBox(False, 0) self.vbox = gtk.VBox(False, 0)
self.vbox.show() self.vbox.show()

View File

@ -20,28 +20,29 @@ import pygtk
pygtk.require('2.0') pygtk.require('2.0')
import gtk import gtk
import os import os
import sys
from time import time, strftime from time import time, strftime
import Card import Card
import fpdb_import import fpdb_import
import Database
import fpdb_db import fpdb_db
import Filters import Filters
import FpdbSQLQueries
class GuiPlayerStats (threading.Thread): class GuiPlayerStats (threading.Thread):
def __init__(self, config, querylist, mainwin, debug=True): def __init__(self, config, querylist, mainwin, debug=True):
self.debug=debug self.debug = debug
self.conf=config self.conf = config
self.main_window=mainwin self.main_window = mainwin
self.sql = querylist
self.MYSQL_INNODB = 2 self.MYSQL_INNODB = 2
self.PGSQL = 3 self.PGSQL = 3
self.SQLITE = 4 self.SQLITE = 4
# create new db connection to avoid conflicts with other threads # create new db connection to avoid conflicts with other threads
self.db = fpdb_db.fpdb_db() self.db = Database.Database(self.conf, sql=self.sql)
self.db.do_connect(self.conf) self.cursor = self.db.cursor
self.cursor=self.db.cursor
self.sql = querylist
settings = {} settings = {}
settings.update(config.get_db_parameters()) settings.update(config.get_db_parameters())
@ -216,7 +217,7 @@ class GuiPlayerStats (threading.Thread):
flags = [True] flags = [True]
self.addTable(vbox1, 'playerDetailedStats', flags, playerids, sitenos, limits, seats, groups, dates) self.addTable(vbox1, 'playerDetailedStats', flags, playerids, sitenos, limits, seats, groups, dates)
self.db.db.commit() self.db.commit()
print "Stats page displayed in %4.2f seconds" % (time() - starttime) print "Stats page displayed in %4.2f seconds" % (time() - starttime)
#end def fillStatsFrame(self, vbox): #end def fillStatsFrame(self, vbox):
@ -280,8 +281,10 @@ class GuiPlayerStats (threading.Thread):
if column[colalias] == 'plposition': if column[colalias] == 'plposition':
if value == 'B': if value == 'B':
value = 'BB' value = 'BB'
if value == 'S': elif value == 'S':
value = 'SB' value = 'SB'
elif value == '0':
value = 'Btn'
else: else:
if column[colalias] == 'game': if column[colalias] == 'game':
if holecards: if holecards:
@ -379,7 +382,8 @@ class GuiPlayerStats (threading.Thread):
# Group by position? # Group by position?
if groups['posn']: if groups['posn']:
query = query.replace("<position>", 'hp.position') #query = query.replace("<position>", "case hp.position when '0' then 'Btn' else hp.position end")
query = query.replace("<position>", "hp.position")
# set flag in self.columns to show posn column # set flag in self.columns to show posn column
[x for x in self.columns if x[0] == 'plposition'][0][1] = True [x for x in self.columns if x[0] == 'plposition'][0][1] = True
else: else:

View File

@ -571,6 +571,183 @@ class Sql:
from Hands from Hands
where handStart < now() at time zone 'UTC' - interval '1 day'""" where handStart < now() at time zone 'UTC' - interval '1 day'"""
#if db_server == 'mysql':
self.query['get_hand_nhands_ago'] = """
select coalesce(greatest(max(id),%s)-%s,0)
from Hands"""
# used in GuiPlayerStats:
self.query['getPlayerId'] = """SELECT id from Players where name = %s"""
# used in Filters:
self.query['getSiteId'] = """SELECT id from Sites where name = %s"""
self.query['getGames'] = """SELECT DISTINCT category from Gametypes"""
self.query['getLimits'] = """SELECT DISTINCT bigBlind from Gametypes ORDER by bigBlind DESC"""
if db_server == 'mysql':
self.query['playerDetailedStats'] = """
select <hgameTypeId> AS hgametypeid
,gt.base
,gt.category
,upper(gt.limitType) AS limittype
,s.name
,min(gt.bigBlind) AS minbigblind
,max(gt.bigBlind) AS maxbigblind
/*,<hcgametypeId> AS gtid*/
,<position> AS plposition
,count(1) AS n
,100.0*sum(cast(hp.street0VPI as <signed>integer))/count(1) AS vpip
,100.0*sum(cast(hp.street0Aggr as <signed>integer))/count(1) AS pfr
,case when sum(cast(hp.street0_3Bchance as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.street0_3Bdone as <signed>integer))/sum(cast(hp.street0_3Bchance as <signed>integer))
end AS pf3
,case when sum(cast(hp.stealattemptchance as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.stealattempted as <signed>integer))/sum(cast(hp.stealattemptchance as <signed>integer))
end AS steals
,100.0*sum(cast(hp.street1Seen as <signed>integer))/count(1) AS saw_f
,100.0*sum(cast(hp.sawShowdown as <signed>integer))/count(1) AS sawsd
,case when sum(cast(hp.street1Seen as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.sawShowdown as <signed>integer))/sum(cast(hp.street1Seen as <signed>integer))
end AS wtsdwsf
,case when sum(cast(hp.sawShowdown as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.wonAtSD as <signed>integer))/sum(cast(hp.sawShowdown as <signed>integer))
end AS wmsd
,case when sum(cast(hp.street1Seen as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.street1Aggr as <signed>integer))/sum(cast(hp.street1Seen as <signed>integer))
end AS flafq
,case when sum(cast(hp.street2Seen as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.street2Aggr as <signed>integer))/sum(cast(hp.street2Seen as <signed>integer))
end AS tuafq
,case when sum(cast(hp.street3Seen as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.street3Aggr as <signed>integer))/sum(cast(hp.street3Seen as <signed>integer))
end AS rvafq
,case when sum(cast(hp.street1Seen as <signed>integer))+sum(cast(hp.street2Seen as <signed>integer))+sum(cast(hp.street3Seen as <signed>integer)) = 0 then -999
else 100.0*(sum(cast(hp.street1Aggr as <signed>integer))+sum(cast(hp.street2Aggr as <signed>integer))+sum(cast(hp.street3Aggr as <signed>integer)))
/(sum(cast(hp.street1Seen as <signed>integer))+sum(cast(hp.street2Seen as <signed>integer))+sum(cast(hp.street3Seen as <signed>integer)))
end AS pofafq
,sum(hp.totalProfit)/100.0 AS net
,sum(hp.rake)/100.0 AS rake
,100.0*avg(hp.totalProfit/(gt.bigBlind+0.0)) AS bbper100
,avg(hp.totalProfit)/100.0 AS profitperhand
,100.0*avg((hp.totalProfit+hp.rake)/(gt.bigBlind+0.0)) AS bb100xr
,avg((hp.totalProfit+hp.rake)/100.0) AS profhndxr
,avg(h.seats+0.0) AS avgseats
,variance(hp.totalProfit/100.0) AS variance
from HandsPlayers hp
inner join Hands h on (h.id = hp.handId)
inner join Gametypes gt on (gt.Id = h.gameTypeId)
inner join Sites s on (s.Id = gt.siteId)
where hp.playerId in <player_test>
and hp.tourneysPlayersId IS NULL
and h.seats <seats_test>
<flagtest>
<gtbigBlind_test>
and date_format(h.handStart, '%Y-%m-%d') <datestest>
group by hgameTypeId
,hp.playerId
,gt.base
,gt.category
<groupbyseats>
,plposition
,upper(gt.limitType)
,s.name
order by hp.playerId
,gt.base
,gt.category
<orderbyseats>
,case <position> when 'B' then 'B'
when 'S' then 'S'
else concat('Z', <position>)
end
<orderbyhgameTypeId>
,maxbigblind desc
,upper(gt.limitType)
,s.name
"""
else: # assume postgresql
self.query['playerDetailedStats'] = """
select <hgameTypeId> AS hgametypeid
,gt.base
,gt.category
,upper(gt.limitType) AS limittype
,s.name
,min(gt.bigBlind) AS minbigblind
,max(gt.bigBlind) AS maxbigblind
/*,<hcgametypeId> AS gtid*/
,<position> AS plposition
,count(1) AS n
,100.0*sum(cast(hp.street0VPI as <signed>integer))/count(1) AS vpip
,100.0*sum(cast(hp.street0Aggr as <signed>integer))/count(1) AS pfr
,case when sum(cast(hp.street0_3Bchance as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.street0_3Bdone as <signed>integer))/sum(cast(hp.street0_3Bchance as <signed>integer))
end AS pf3
,case when sum(cast(hp.stealattemptchance as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.stealattempted as <signed>integer))/sum(cast(hp.stealattemptchance as <signed>integer))
end AS steals
,100.0*sum(cast(hp.street1Seen as <signed>integer))/count(1) AS saw_f
,100.0*sum(cast(hp.sawShowdown as <signed>integer))/count(1) AS sawsd
,case when sum(cast(hp.street1Seen as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.sawShowdown as <signed>integer))/sum(cast(hp.street1Seen as <signed>integer))
end AS wtsdwsf
,case when sum(cast(hp.sawShowdown as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.wonAtSD as <signed>integer))/sum(cast(hp.sawShowdown as <signed>integer))
end AS wmsd
,case when sum(cast(hp.street1Seen as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.street1Aggr as <signed>integer))/sum(cast(hp.street1Seen as <signed>integer))
end AS flafq
,case when sum(cast(hp.street2Seen as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.street2Aggr as <signed>integer))/sum(cast(hp.street2Seen as <signed>integer))
end AS tuafq
,case when sum(cast(hp.street3Seen as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.street3Aggr as <signed>integer))/sum(cast(hp.street3Seen as <signed>integer))
end AS rvafq
,case when sum(cast(hp.street1Seen as <signed>integer))+sum(cast(hp.street2Seen as <signed>integer))+sum(cast(hp.street3Seen as <signed>integer)) = 0 then -999
else 100.0*(sum(cast(hp.street1Aggr as <signed>integer))+sum(cast(hp.street2Aggr as <signed>integer))+sum(cast(hp.street3Aggr as <signed>integer)))
/(sum(cast(hp.street1Seen as <signed>integer))+sum(cast(hp.street2Seen as <signed>integer))+sum(cast(hp.street3Seen as <signed>integer)))
end AS pofafq
,sum(hp.totalProfit)/100.0 AS net
,sum(hp.rake)/100.0 AS rake
,100.0*avg(hp.totalProfit/(gt.bigBlind+0.0)) AS bbper100
,avg(hp.totalProfit)/100.0 AS profitperhand
,100.0*avg((hp.totalProfit+hp.rake)/(gt.bigBlind+0.0)) AS bb100xr
,avg((hp.totalProfit+hp.rake)/100.0) AS profhndxr
,avg(h.seats+0.0) AS avgseats
,variance(hp.totalProfit/100.0) AS variance
from HandsPlayers hp
inner join Hands h on (h.id = hp.handId)
inner join Gametypes gt on (gt.Id = h.gameTypeId)
inner join Sites s on (s.Id = gt.siteId)
where hp.playerId in <player_test>
and hp.tourneysPlayersId IS NULL
and h.seats <seats_test>
<flagtest>
<gtbigBlind_test>
and to_char(h.handStart, 'YYYY-MM-DD') <datestest>
group by hgameTypeId
,hp.playerId
,gt.base
,gt.category
<groupbyseats>
,plposition
,upper(gt.limitType)
,s.name
order by hp.playerId
,gt.base
,gt.category
<orderbyseats>
,case <position> when 'B' then 'B'
when 'S' then 'S'
when '0' then 'Y'
else 'Z'||<position>
end
<orderbyhgameTypeId>
,maxbigblind desc
,upper(gt.limitType)
,s.name
"""
#elif(self.dbname == 'SQLite'):
# self.query['playerDetailedStats'] = """ """
if __name__== "__main__": if __name__== "__main__":
# just print the default queries and exit # just print the default queries and exit
s = Sql(game = 'razz', type = 'ptracks') s = Sql(game = 'razz', type = 'ptracks')

View File

@ -17,6 +17,7 @@
import os import os
import sys import sys
import threading
import Options import Options
import string import string
cl_options = string.join(sys.argv[1:]) cl_options = string.join(sys.argv[1:])
@ -116,11 +117,13 @@ class fpdb:
def dia_create_del_database(self, widget, data=None): def dia_create_del_database(self, widget, data=None):
print "todo: implement dia_create_del_database" print "todo: implement dia_create_del_database"
self.obtain_global_lock() self.obtain_global_lock()
self.release_global_lock()
#end def dia_create_del_database #end def dia_create_del_database
def dia_create_del_user(self, widget, data=None): def dia_create_del_user(self, widget, data=None):
print "todo: implement dia_create_del_user" print "todo: implement dia_create_del_user"
self.obtain_global_lock() self.obtain_global_lock()
self.release_global_lock()
#end def dia_create_del_user #end def dia_create_del_user
def dia_database_stats(self, widget, data=None): def dia_database_stats(self, widget, data=None):
@ -137,16 +140,19 @@ class fpdb:
def dia_delete_db_parts(self, widget, data=None): def dia_delete_db_parts(self, widget, data=None):
print "todo: implement dia_delete_db_parts" print "todo: implement dia_delete_db_parts"
self.obtain_global_lock() self.obtain_global_lock()
self.release_global_lock()
#end def dia_delete_db_parts #end def dia_delete_db_parts
def dia_edit_profile(self, widget=None, data=None, create_default=False, path=None): def dia_edit_profile(self, widget=None, data=None, create_default=False, path=None):
print "todo: implement dia_edit_profile" print "todo: implement dia_edit_profile"
self.obtain_global_lock() self.obtain_global_lock()
self.release_global_lock()
#end def dia_edit_profile #end def dia_edit_profile
def dia_export_db(self, widget, data=None): def dia_export_db(self, widget, data=None):
print "todo: implement dia_export_db" print "todo: implement dia_export_db"
self.obtain_global_lock() self.obtain_global_lock()
self.release_global_lock()
#end def dia_export_db #end def dia_export_db
def dia_get_db_root_credentials(self): def dia_get_db_root_credentials(self):
@ -172,6 +178,7 @@ class fpdb:
def dia_import_db(self, widget, data=None): def dia_import_db(self, widget, data=None):
print "todo: implement dia_import_db" print "todo: implement dia_import_db"
self.obtain_global_lock() self.obtain_global_lock()
self.release_global_lock()
#end def dia_import_db #end def dia_import_db
def dia_licensing(self, widget, data=None): def dia_licensing(self, widget, data=None):
@ -180,7 +187,7 @@ class fpdb:
def dia_load_profile(self, widget, data=None): def dia_load_profile(self, widget, data=None):
"""Dialogue to select a file to load a profile from""" """Dialogue to select a file to load a profile from"""
if self.obtain_global_lock() == 0: # returns 0 if successful if self.obtain_global_lock(): # returns true if successful
#try: #try:
# chooser = gtk.FileChooserDialog(title="Please select a profile file to load", # chooser = gtk.FileChooserDialog(title="Please select a profile file to load",
# action=gtk.FILE_CHOOSER_ACTION_OPEN, # action=gtk.FILE_CHOOSER_ACTION_OPEN,
@ -195,15 +202,18 @@ class fpdb:
# print 'User cancelled loading profile' # print 'User cancelled loading profile'
#except: #except:
# pass # pass
self.load_profile() try:
self.load_profile()
except:
pass
self.release_global_lock() self.release_global_lock()
#end def dia_load_profile #end def dia_load_profile
def dia_recreate_tables(self, widget, data=None): def dia_recreate_tables(self, widget, data=None):
"""Dialogue that asks user to confirm that he wants to delete and recreate the tables""" """Dialogue that asks user to confirm that he wants to delete and recreate the tables"""
if self.obtain_global_lock() in (0,2): # returns 0 if successful, 2 if Hands table does not exist if self.obtain_global_lock(): # returns true if successful
lock_released = False #lock_released = False
try: try:
dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING,
buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm deleting and recreating tables") buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm deleting and recreating tables")
@ -214,27 +224,28 @@ class fpdb:
response = dia_confirm.run() response = dia_confirm.run()
dia_confirm.destroy() dia_confirm.destroy()
if response == gtk.RESPONSE_YES: if response == gtk.RESPONSE_YES:
if self.db.fdb.backend == self.fdb_lock.fdb.MYSQL_INNODB: #if self.db.fdb.backend == self.fdb_lock.fdb.MYSQL_INNODB:
# mysql requires locks on all tables or none - easier to release this lock # mysql requires locks on all tables or none - easier to release this lock
# than lock all the other tables # than lock all the other tables
# ToDo: lock all other tables so that lock doesn't have to be released # ToDo: lock all other tables so that lock doesn't have to be released
self.release_global_lock() # self.release_global_lock()
lock_released = True # lock_released = True
self.db.fdb.recreate_tables() self.db.fdb.recreate_tables()
else: #else:
# for other dbs use same connection as holds global lock # for other dbs use same connection as holds global lock
self.fdb_lock.fdb.recreate_tables() # self.fdb_lock.fdb.recreate_tables()
elif response == gtk.RESPONSE_NO: elif response == gtk.RESPONSE_NO:
print 'User cancelled recreating tables' print 'User cancelled recreating tables'
except: except:
pass pass
if not lock_released: #if not lock_released:
self.release_global_lock() self.release_global_lock()
#end def dia_recreate_tables #end def dia_recreate_tables
def dia_regression_test(self, widget, data=None): def dia_regression_test(self, widget, data=None):
print "todo: implement dia_regression_test" print "todo: implement dia_regression_test"
self.obtain_global_lock() self.obtain_global_lock()
self.release_global_lock()
#end def dia_regression_test #end def dia_regression_test
def dia_save_profile(self, widget, data=None): def dia_save_profile(self, widget, data=None):
@ -353,6 +364,7 @@ class fpdb:
"""Loads profile from the provided path name.""" """Loads profile from the provided path name."""
self.config = Configuration.Config(file=options.config, dbname=options.dbname) self.config = Configuration.Config(file=options.config, dbname=options.dbname)
self.settings = {} self.settings = {}
self.settings['global_lock'] = self.lock
if (os.sep=="/"): if (os.sep=="/"):
self.settings['os']="linuxmac" self.settings['os']="linuxmac"
else: else:
@ -405,10 +417,15 @@ class fpdb:
#end def not_implemented #end def not_implemented
def obtain_global_lock(self): def obtain_global_lock(self):
print "\nTaking global lock ..." ret = self.lock.acquire(False) # will return false if lock is already held
self.fdb_lock = Database.Database(self.config, sql = self.sql) if ret:
self.fdb_lock.do_connect(self.config) print "\nGlobal lock taken ..."
return self.fdb_lock.fdb.get_global_lock() else:
print "\nFailed to get global lock."
return ret
# need to release it later:
# self.lock.release()
#end def obtain_global_lock #end def obtain_global_lock
def quit(self, widget, data=None): def quit(self, widget, data=None):
@ -419,8 +436,7 @@ class fpdb:
#end def quit_cliecked #end def quit_cliecked
def release_global_lock(self): def release_global_lock(self):
self.fdb_lock.fdb.db.rollback() self.lock.release()
self.fdb_lock.fdb.disconnect()
print "Global lock released.\n" print "Global lock released.\n"
#end def release_global_lock #end def release_global_lock
@ -446,7 +462,7 @@ class fpdb:
#end def tab_bulk_import #end def tab_bulk_import
def tab_player_stats(self, widget, data=None): def tab_player_stats(self, widget, data=None):
new_ps_thread=GuiPlayerStats.GuiPlayerStats(self.config, self.querydict, self.window) new_ps_thread=GuiPlayerStats.GuiPlayerStats(self.config, self.sql, self.window)
self.threads.append(new_ps_thread) self.threads.append(new_ps_thread)
ps_tab=new_ps_thread.get_vbox() ps_tab=new_ps_thread.get_vbox()
self.add_and_display_tab(ps_tab, "Player Stats") self.add_and_display_tab(ps_tab, "Player Stats")
@ -487,6 +503,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
def __init__(self): def __init__(self):
self.threads = [] self.threads = []
self.lock = threading.Lock()
self.db = None self.db = None
self.status_bar = None self.status_bar = None