diff options
Diffstat (limited to 'bitbake/lib/prserv/db.py')
-rw-r--r-- | bitbake/lib/prserv/db.py | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/bitbake/lib/prserv/db.py b/bitbake/lib/prserv/db.py new file mode 100644 index 0000000000..86eafe338c --- /dev/null +++ b/bitbake/lib/prserv/db.py | |||
@@ -0,0 +1,242 @@ | |||
1 | import logging | ||
2 | import os.path | ||
3 | import errno | ||
4 | import prserv | ||
5 | import time | ||
6 | |||
7 | try: | ||
8 | import sqlite3 | ||
9 | except ImportError: | ||
10 | from pysqlite2 import dbapi2 as sqlite3 | ||
11 | |||
12 | logger = logging.getLogger("BitBake.PRserv") | ||
13 | |||
14 | sqlversion = sqlite3.sqlite_version_info | ||
15 | if sqlversion[0] < 3 or (sqlversion[0] == 3 and sqlversion[1] < 3): | ||
16 | raise Exception("sqlite3 version 3.3.0 or later is required.") | ||
17 | |||
18 | class PRTable(object): | ||
19 | def __init__(self, conn, table, nohist): | ||
20 | self.conn = conn | ||
21 | self.nohist = nohist | ||
22 | if nohist: | ||
23 | self.table = "%s_nohist" % table | ||
24 | else: | ||
25 | self.table = "%s_hist" % table | ||
26 | |||
27 | self._execute("CREATE TABLE IF NOT EXISTS %s \ | ||
28 | (version TEXT NOT NULL, \ | ||
29 | pkgarch TEXT NOT NULL, \ | ||
30 | checksum TEXT NOT NULL, \ | ||
31 | value INTEGER, \ | ||
32 | PRIMARY KEY (version, pkgarch, checksum));" % self.table) | ||
33 | |||
34 | def _execute(self, *query): | ||
35 | """Execute a query, waiting to acquire a lock if necessary""" | ||
36 | start = time.time() | ||
37 | end = start + 20 | ||
38 | while True: | ||
39 | try: | ||
40 | return self.conn.execute(*query) | ||
41 | except sqlite3.OperationalError as exc: | ||
42 | if 'is locked' in str(exc) and end > time.time(): | ||
43 | continue | ||
44 | raise exc | ||
45 | |||
46 | def sync(self): | ||
47 | self.conn.commit() | ||
48 | self._execute("BEGIN EXCLUSIVE TRANSACTION") | ||
49 | |||
50 | def _getValueHist(self, version, pkgarch, checksum): | ||
51 | data=self._execute("SELECT value FROM %s WHERE version=? AND pkgarch=? AND checksum=?;" % self.table, | ||
52 | (version, pkgarch, checksum)) | ||
53 | row=data.fetchone() | ||
54 | if row != None: | ||
55 | return row[0] | ||
56 | else: | ||
57 | #no value found, try to insert | ||
58 | try: | ||
59 | self._execute("INSERT INTO %s VALUES (?, ?, ?, (select ifnull(max(value)+1,0) from %s where version=? AND pkgarch=?));" | ||
60 | % (self.table,self.table), | ||
61 | (version,pkgarch, checksum,version, pkgarch)) | ||
62 | except sqlite3.IntegrityError as exc: | ||
63 | logger.error(str(exc)) | ||
64 | |||
65 | data=self._execute("SELECT value FROM %s WHERE version=? AND pkgarch=? AND checksum=?;" % self.table, | ||
66 | (version, pkgarch, checksum)) | ||
67 | row=data.fetchone() | ||
68 | if row != None: | ||
69 | return row[0] | ||
70 | else: | ||
71 | raise prserv.NotFoundError | ||
72 | |||
73 | def _getValueNohist(self, version, pkgarch, checksum): | ||
74 | data=self._execute("SELECT value FROM %s \ | ||
75 | WHERE version=? AND pkgarch=? AND checksum=? AND \ | ||
76 | value >= (select max(value) from %s where version=? AND pkgarch=?);" | ||
77 | % (self.table, self.table), | ||
78 | (version, pkgarch, checksum, version, pkgarch)) | ||
79 | row=data.fetchone() | ||
80 | if row != None: | ||
81 | return row[0] | ||
82 | else: | ||
83 | #no value found, try to insert | ||
84 | try: | ||
85 | self._execute("INSERT OR REPLACE INTO %s VALUES (?, ?, ?, (select ifnull(max(value)+1,0) from %s where version=? AND pkgarch=?));" | ||
86 | % (self.table,self.table), | ||
87 | (version, pkgarch, checksum, version, pkgarch)) | ||
88 | except sqlite3.IntegrityError as exc: | ||
89 | logger.error(str(exc)) | ||
90 | self.conn.rollback() | ||
91 | |||
92 | data=self._execute("SELECT value FROM %s WHERE version=? AND pkgarch=? AND checksum=?;" % self.table, | ||
93 | (version, pkgarch, checksum)) | ||
94 | row=data.fetchone() | ||
95 | if row != None: | ||
96 | return row[0] | ||
97 | else: | ||
98 | raise prserv.NotFoundError | ||
99 | |||
100 | def getValue(self, version, pkgarch, checksum): | ||
101 | if self.nohist: | ||
102 | return self._getValueNohist(version, pkgarch, checksum) | ||
103 | else: | ||
104 | return self._getValueHist(version, pkgarch, checksum) | ||
105 | |||
106 | def _importHist(self, version, pkgarch, checksum, value): | ||
107 | val = None | ||
108 | data = self._execute("SELECT value FROM %s WHERE version=? AND pkgarch=? AND checksum=?;" % self.table, | ||
109 | (version, pkgarch, checksum)) | ||
110 | row = data.fetchone() | ||
111 | if row != None: | ||
112 | val=row[0] | ||
113 | else: | ||
114 | #no value found, try to insert | ||
115 | try: | ||
116 | self._execute("INSERT INTO %s VALUES (?, ?, ?, ?);" % (self.table), | ||
117 | (version, pkgarch, checksum, value)) | ||
118 | except sqlite3.IntegrityError as exc: | ||
119 | logger.error(str(exc)) | ||
120 | |||
121 | data = self._execute("SELECT value FROM %s WHERE version=? AND pkgarch=? AND checksum=?;" % self.table, | ||
122 | (version, pkgarch, checksum)) | ||
123 | row = data.fetchone() | ||
124 | if row != None: | ||
125 | val = row[0] | ||
126 | return val | ||
127 | |||
128 | def _importNohist(self, version, pkgarch, checksum, value): | ||
129 | try: | ||
130 | #try to insert | ||
131 | self._execute("INSERT INTO %s VALUES (?, ?, ?, ?);" % (self.table), | ||
132 | (version, pkgarch, checksum,value)) | ||
133 | except sqlite3.IntegrityError as exc: | ||
134 | #already have the record, try to update | ||
135 | try: | ||
136 | self._execute("UPDATE %s SET value=? WHERE version=? AND pkgarch=? AND checksum=? AND value<?" | ||
137 | % (self.table), | ||
138 | (value,version,pkgarch,checksum,value)) | ||
139 | except sqlite3.IntegrityError as exc: | ||
140 | logger.error(str(exc)) | ||
141 | |||
142 | data = self._execute("SELECT value FROM %s WHERE version=? AND pkgarch=? AND checksum=? AND value>=?;" % self.table, | ||
143 | (version,pkgarch,checksum,value)) | ||
144 | row=data.fetchone() | ||
145 | if row != None: | ||
146 | return row[0] | ||
147 | else: | ||
148 | return None | ||
149 | |||
150 | def importone(self, version, pkgarch, checksum, value): | ||
151 | if self.nohist: | ||
152 | return self._importNohist(version, pkgarch, checksum, value) | ||
153 | else: | ||
154 | return self._importHist(version, pkgarch, checksum, value) | ||
155 | |||
156 | def export(self, version, pkgarch, checksum, colinfo): | ||
157 | metainfo = {} | ||
158 | #column info | ||
159 | if colinfo: | ||
160 | metainfo['tbl_name'] = self.table | ||
161 | metainfo['core_ver'] = prserv.__version__ | ||
162 | metainfo['col_info'] = [] | ||
163 | data = self._execute("PRAGMA table_info(%s);" % self.table) | ||
164 | for row in data: | ||
165 | col = {} | ||
166 | col['name'] = row['name'] | ||
167 | col['type'] = row['type'] | ||
168 | col['notnull'] = row['notnull'] | ||
169 | col['dflt_value'] = row['dflt_value'] | ||
170 | col['pk'] = row['pk'] | ||
171 | metainfo['col_info'].append(col) | ||
172 | |||
173 | #data info | ||
174 | datainfo = [] | ||
175 | |||
176 | if self.nohist: | ||
177 | sqlstmt = "SELECT T1.version, T1.pkgarch, T1.checksum, T1.value FROM %s as T1, \ | ||
178 | (SELECT version,pkgarch,max(value) as maxvalue FROM %s GROUP BY version,pkgarch) as T2 \ | ||
179 | WHERE T1.version=T2.version AND T1.pkgarch=T2.pkgarch AND T1.value=T2.maxvalue " % (self.table, self.table) | ||
180 | else: | ||
181 | sqlstmt = "SELECT * FROM %s as T1 WHERE 1=1 " % self.table | ||
182 | sqlarg = [] | ||
183 | where = "" | ||
184 | if version: | ||
185 | where += "AND T1.version=? " | ||
186 | sqlarg.append(str(version)) | ||
187 | if pkgarch: | ||
188 | where += "AND T1.pkgarch=? " | ||
189 | sqlarg.append(str(pkgarch)) | ||
190 | if checksum: | ||
191 | where += "AND T1.checksum=? " | ||
192 | sqlarg.append(str(checksum)) | ||
193 | |||
194 | sqlstmt += where + ";" | ||
195 | |||
196 | if len(sqlarg): | ||
197 | data = self._execute(sqlstmt, tuple(sqlarg)) | ||
198 | else: | ||
199 | data = self._execute(sqlstmt) | ||
200 | for row in data: | ||
201 | if row['version']: | ||
202 | col = {} | ||
203 | col['version'] = row['version'] | ||
204 | col['pkgarch'] = row['pkgarch'] | ||
205 | col['checksum'] = row['checksum'] | ||
206 | col['value'] = row['value'] | ||
207 | datainfo.append(col) | ||
208 | return (metainfo, datainfo) | ||
209 | |||
210 | class PRData(object): | ||
211 | """Object representing the PR database""" | ||
212 | def __init__(self, filename, nohist=True): | ||
213 | self.filename=os.path.abspath(filename) | ||
214 | self.nohist=nohist | ||
215 | #build directory hierarchy | ||
216 | try: | ||
217 | os.makedirs(os.path.dirname(self.filename)) | ||
218 | except OSError as e: | ||
219 | if e.errno != errno.EEXIST: | ||
220 | raise e | ||
221 | self.connection=sqlite3.connect(self.filename, isolation_level="EXCLUSIVE", check_same_thread = False) | ||
222 | self.connection.row_factory=sqlite3.Row | ||
223 | self._tables={} | ||
224 | |||
225 | def __del__(self): | ||
226 | self.connection.close() | ||
227 | |||
228 | def __getitem__(self,tblname): | ||
229 | if not isinstance(tblname, basestring): | ||
230 | raise TypeError("tblname argument must be a string, not '%s'" % | ||
231 | type(tblname)) | ||
232 | if tblname in self._tables: | ||
233 | return self._tables[tblname] | ||
234 | else: | ||
235 | tableobj = self._tables[tblname] = PRTable(self.connection, tblname, self.nohist) | ||
236 | return tableobj | ||
237 | |||
238 | def __delitem__(self, tblname): | ||
239 | if tblname in self._tables: | ||
240 | del self._tables[tblname] | ||
241 | logger.info("drop table %s" % (tblname)) | ||
242 | self.connection.execute("DROP TABLE IF EXISTS %s;" % tblname) | ||