instrumentation: add next-share/
[cs-p2p-next.git] / instrumentation / next-share / BaseLib / Core / CacheDB / SqliteSeedingStatsCacheDB.py
1 # Written by Boxun Zhang
2 # see LICENSE.txt for license information
3
4 import os
5 from time import time
6 import threading
7 from traceback import print_exc
8
9 from BaseLib.__init__ import LIBRARYNAME
10 from BaseLib.Core.CacheDB.sqlitecachedb import *
11 from BaseLib.Core.CacheDB.SqliteCacheDBHandler import BasicDBHandler
12 from BaseLib.Core.simpledefs import *
13
14 CREATE_SEEDINGSTATS_SQL_FILE = None
15 CREATE_SEEDINGSTATS_SQL_FILE_POSTFIX = os.path.join(LIBRARYNAME, 'Core', 'Statistics', 'tribler_seedingstats_sdb.sql')
16 DB_FILE_NAME = 'tribler_seedingstats.sdb'
17 DB_DIR_NAME = 'sqlite'    # db file path = DB_DIR_NAME/DB_FILE_NAME
18 CURRENT_DB_VERSION = 1
19 DEFAULT_BUSY_TIMEOUT = 10000
20 MAX_SQL_BATCHED_TO_TRANSACTION = 1000   # don't change it unless carefully tested. A transaction with 1000 batched updates took 1.5 seconds
21 SHOW_ALL_EXECUTE = False
22 costs = []
23 cost_reads = []
24
25 DEBUG = False
26
27 def init_seeding_stats(config, db_exception_handler = None):
28     """ create SeedingStats database """
29     global CREATE_SEEDINGSTATS_SQL_FILE
30     config_dir = config['state_dir']
31     install_dir = config['install_dir']
32     CREATE_SEEDINGSTATS_SQL_FILE = os.path.join(install_dir,CREATE_SEEDINGSTATS_SQL_FILE_POSTFIX)
33     sqlitedb = SQLiteSeedingStatsCacheDB.getInstance(db_exception_handler)   
34     sqlite_db_path = os.path.join(config_dir, DB_DIR_NAME, DB_FILE_NAME)
35     sqlitedb.initDB(sqlite_db_path, CREATE_SEEDINGSTATS_SQL_FILE)  # the first place to create db in Tribler
36     return sqlitedb
37
38 class SQLiteSeedingStatsCacheDB(SQLiteCacheDBBase):
39     __single = None    # used for multithreaded singletons pattern
40     lock = threading.RLock()
41     
42     @classmethod
43     def getInstance(cls, *args, **kw):
44         # Singleton pattern with double-checking to ensure that it can only create one object
45         if cls.__single is None:
46             cls.lock.acquire()   
47             try:
48                 if cls.__single is None:
49                     cls.__single = cls(*args, **kw)
50             finally:
51                 cls.lock.release()
52         return cls.__single
53
54     def __init__(self, *args, **kw):
55         # always use getInstance() to create this object
56         if self.__single != None:
57             raise RuntimeError, "SQLiteSeedingStatsCacheDB is singleton"
58         
59         SQLiteCacheDBBase.__init__(self, *args, **kw)
60     
61     
62 class SeedingStatsDBHandler(BasicDBHandler):
63     
64     __single = None    # used for multithreaded singletons pattern
65     lock = threading.Lock()
66     
67     def getInstance(*args, **kw):
68         # Singleton pattern with double-checking
69         if SeedingStatsDBHandler.__single is None:
70             SeedingStatsDBHandler.lock.acquire()   
71             try:
72                 if SeedingStatsDBHandler.__single is None:
73                     SeedingStatsDBHandler(*args, **kw)
74             finally:
75                 SeedingStatsDBHandler.lock.release()
76         return SeedingStatsDBHandler.__single
77     
78     getInstance = staticmethod(getInstance)
79     
80     def __init__(self):
81         if SeedingStatsDBHandler.__single is not None:
82             raise RuntimeError, "SeedingStatDBHandler is singleton"
83         SeedingStatsDBHandler.__single = self
84         db = SQLiteSeedingStatsCacheDB.getInstance()
85         BasicDBHandler.__init__(self, db, 'SeedingStats')
86     
87     def updateSeedingStats(self, permID, reputation, dslist, interval):
88         permID = bin2str(permID)
89         
90         seedings = []
91         
92         for item in dslist:
93             if item.get_status() == DLSTATUS_SEEDING:
94                 seedings.append(item)
95                 
96         commit = False
97         for i in range(0, len(seedings)):
98             ds = seedings[i]
99             
100             infohash = bin2str(ds.get_download().get_def().get_infohash())
101             
102             stats = ds.stats['stats']
103             ul = stats.upTotal
104                 
105             if i == len(seedings)-1:
106                 commit = True
107                 
108             res = self.existedInfoHash(infohash)
109                 
110             if res is not None:
111                 # res is list of ONE tuple
112                 #self.updateSeedingStat(infohash, reputation, res[0][0], interval, commit)
113                 
114                 # NAT/Firewall & Seeding Behavior
115                 # Store upload amount instead peer reputation
116                 self.updateSeedingStat(infohash, ul, res[0][0], interval, commit)
117             else:
118                 # Insert new record
119                 #self.insertSeedingStat(infohash, permID, reputation, interval, commit)
120                 
121                 # NAT/Firewall & Seeding Behavior
122                 # Store upload amount instead peer reputation
123                 self.insertSeedingStat(infohash, permID, ul, interval, commit)
124             
125     
126     def existedInfoHash(self, infohash):
127                 
128         sql = "SELECT seeding_time FROM SeedingStats WHERE info_hash='%s' and crawled=0"%infohash
129         
130         try:
131             cursor = self._db.execute_read(sql)
132             if cursor:
133                 res = list(cursor)
134                 
135                 if len(res) > 0:
136                     return res
137                 else:
138                     return None
139             else:
140                 # something wrong, throw an exception?
141                 return None
142         except:
143             return None
144     
145     def updateSeedingStat(self, infohash, reputation, seedingtime, interval, commit): 
146         try:
147             sql_update = "UPDATE SeedingStats SET seeding_time=%s, reputation=%s WHERE info_hash='%s' AND crawled=0"%(seedingtime + interval, reputation, infohash)
148             self._db.execute_write(sql_update, None, commit)
149         except:
150             print_exc()
151     
152     def insertSeedingStat(self, infohash, permID, reputation, interval, commit):
153         try:
154             sql_insert = "INSERT INTO SeedingStats VALUES(%s, '%s', '%s', %s, %s, %s)"%(time(), permID, infohash, interval, reputation, 0)
155             self._db.execute_write(sql_insert, None, commit)
156         except:
157             print_exc()
158
159
160 class SeedingStatsSettingsDBHandler(BasicDBHandler):
161     
162     __single = None    # used for multithreaded singletons pattern
163     lock = threading.Lock()
164     
165     def getInstance(*args, **kw):
166         # Singleton pattern with double-checking
167         if SeedingStatsSettingsDBHandler.__single is None:
168             SeedingStatsSettingsDBHandler.lock.acquire()   
169             try:
170                 if SeedingStatsSettingsDBHandler.__single is None:
171                     SeedingStatsSettingsDBHandler(*args, **kw)
172             finally:
173                 SeedingStatsSettingsDBHandler.lock.release()
174         return SeedingStatsSettingsDBHandler.__single
175     
176     getInstance = staticmethod(getInstance)
177     
178     def __init__(self):
179         if SeedingStatsSettingsDBHandler.__single is not None:
180             raise RuntimeError, "SeedingStatDBHandler is singleton"
181         SeedingStatsSettingsDBHandler.__single = self
182         db = SQLiteSeedingStatsCacheDB.getInstance()
183         BasicDBHandler.__init__(self, db, 'CrawlingSettings')
184     
185     def loadCrawlingSettings(self):
186         try:
187             sql_query = "SELECT * FROM SeedingStatsSettings"
188             cursor = self._db.execute_read(sql_query)
189             
190             if cursor:
191                 return list(cursor)
192             else:
193                 return None
194         except:
195             print_exc()
196     
197     def updateCrawlingSettings(self, args):
198         try:
199             sql_update = "UPDATE SeedingStatsSettings SET crawling_interval=%s, crawling_enabled=%s WHERE version=1"%(args[0], args[1])
200             cursor = self._db.execute_write(sql_update)
201         except:
202             print_exc()