diff options
Diffstat (limited to 'bitbake/lib/prserv/db.py')
-rw-r--r-- | bitbake/lib/prserv/db.py | 193 |
1 files changed, 137 insertions, 56 deletions
diff --git a/bitbake/lib/prserv/db.py b/bitbake/lib/prserv/db.py index cb2a2461e0..eb41508198 100644 --- a/bitbake/lib/prserv/db.py +++ b/bitbake/lib/prserv/db.py | |||
@@ -1,4 +1,6 @@ | |||
1 | # | 1 | # |
2 | # Copyright BitBake Contributors | ||
3 | # | ||
2 | # SPDX-License-Identifier: GPL-2.0-only | 4 | # SPDX-License-Identifier: GPL-2.0-only |
3 | # | 5 | # |
4 | 6 | ||
@@ -30,21 +32,29 @@ if sqlversion[0] < 3 or (sqlversion[0] == 3 and sqlversion[1] < 3): | |||
30 | # | 32 | # |
31 | 33 | ||
32 | class PRTable(object): | 34 | class PRTable(object): |
33 | def __init__(self, conn, table, nohist): | 35 | def __init__(self, conn, table, nohist, read_only): |
34 | self.conn = conn | 36 | self.conn = conn |
35 | self.nohist = nohist | 37 | self.nohist = nohist |
38 | self.read_only = read_only | ||
36 | self.dirty = False | 39 | self.dirty = False |
37 | if nohist: | 40 | if nohist: |
38 | self.table = "%s_nohist" % table | 41 | self.table = "%s_nohist" % table |
39 | else: | 42 | else: |
40 | self.table = "%s_hist" % table | 43 | self.table = "%s_hist" % table |
41 | 44 | ||
42 | self._execute("CREATE TABLE IF NOT EXISTS %s \ | 45 | if self.read_only: |
43 | (version TEXT NOT NULL, \ | 46 | table_exists = self._execute( |
44 | pkgarch TEXT NOT NULL, \ | 47 | "SELECT count(*) FROM sqlite_master \ |
45 | checksum TEXT NOT NULL, \ | 48 | WHERE type='table' AND name='%s'" % (self.table)) |
46 | value INTEGER, \ | 49 | if not table_exists: |
47 | PRIMARY KEY (version, pkgarch, checksum));" % self.table) | 50 | raise prserv.NotFoundError |
51 | else: | ||
52 | self._execute("CREATE TABLE IF NOT EXISTS %s \ | ||
53 | (version TEXT NOT NULL, \ | ||
54 | pkgarch TEXT NOT NULL, \ | ||
55 | checksum TEXT NOT NULL, \ | ||
56 | value INTEGER, \ | ||
57 | PRIMARY KEY (version, pkgarch, checksum));" % self.table) | ||
48 | 58 | ||
49 | def _execute(self, *query): | 59 | def _execute(self, *query): |
50 | """Execute a query, waiting to acquire a lock if necessary""" | 60 | """Execute a query, waiting to acquire a lock if necessary""" |
@@ -54,20 +64,67 @@ class PRTable(object): | |||
54 | try: | 64 | try: |
55 | return self.conn.execute(*query) | 65 | return self.conn.execute(*query) |
56 | except sqlite3.OperationalError as exc: | 66 | except sqlite3.OperationalError as exc: |
57 | if 'is locked' in str(exc) and end > time.time(): | 67 | if "is locked" in str(exc) and end > time.time(): |
58 | continue | 68 | continue |
59 | raise exc | 69 | raise exc |
60 | 70 | ||
61 | def sync(self): | 71 | def sync(self): |
62 | self.conn.commit() | 72 | if not self.read_only: |
63 | self._execute("BEGIN EXCLUSIVE TRANSACTION") | 73 | self.conn.commit() |
74 | self._execute("BEGIN EXCLUSIVE TRANSACTION") | ||
64 | 75 | ||
65 | def sync_if_dirty(self): | 76 | def sync_if_dirty(self): |
66 | if self.dirty: | 77 | if self.dirty: |
67 | self.sync() | 78 | self.sync() |
68 | self.dirty = False | 79 | self.dirty = False |
69 | 80 | ||
70 | def _getValueHist(self, version, pkgarch, checksum): | 81 | def test_package(self, version, pkgarch): |
82 | """Returns whether the specified package version is found in the database for the specified architecture""" | ||
83 | |||
84 | # Just returns the value if found or None otherwise | ||
85 | data=self._execute("SELECT value FROM %s WHERE version=? AND pkgarch=?;" % self.table, | ||
86 | (version, pkgarch)) | ||
87 | row=data.fetchone() | ||
88 | if row is not None: | ||
89 | return True | ||
90 | else: | ||
91 | return False | ||
92 | |||
93 | def test_value(self, version, pkgarch, value): | ||
94 | """Returns whether the specified value is found in the database for the specified package and architecture""" | ||
95 | |||
96 | # Just returns the value if found or None otherwise | ||
97 | data=self._execute("SELECT value FROM %s WHERE version=? AND pkgarch=? and value=?;" % self.table, | ||
98 | (version, pkgarch, value)) | ||
99 | row=data.fetchone() | ||
100 | if row is not None: | ||
101 | return True | ||
102 | else: | ||
103 | return False | ||
104 | |||
105 | def find_value(self, version, pkgarch, checksum): | ||
106 | """Returns the value for the specified checksum if found or None otherwise.""" | ||
107 | |||
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 is not None: | ||
112 | return row[0] | ||
113 | else: | ||
114 | return None | ||
115 | |||
116 | def find_max_value(self, version, pkgarch): | ||
117 | """Returns the greatest value for (version, pkgarch), or None if not found. Doesn't create a new value""" | ||
118 | |||
119 | data = self._execute("SELECT max(value) FROM %s where version=? AND pkgarch=?;" % (self.table), | ||
120 | (version, pkgarch)) | ||
121 | row = data.fetchone() | ||
122 | if row is not None: | ||
123 | return row[0] | ||
124 | else: | ||
125 | return None | ||
126 | |||
127 | def _get_value_hist(self, version, pkgarch, checksum): | ||
71 | data=self._execute("SELECT value FROM %s WHERE version=? AND pkgarch=? AND checksum=?;" % self.table, | 128 | data=self._execute("SELECT value FROM %s WHERE version=? AND pkgarch=? AND checksum=?;" % self.table, |
72 | (version, pkgarch, checksum)) | 129 | (version, pkgarch, checksum)) |
73 | row=data.fetchone() | 130 | row=data.fetchone() |
@@ -75,10 +132,19 @@ class PRTable(object): | |||
75 | return row[0] | 132 | return row[0] |
76 | else: | 133 | else: |
77 | #no value found, try to insert | 134 | #no value found, try to insert |
135 | if self.read_only: | ||
136 | data = self._execute("SELECT ifnull(max(value)+1, 0) FROM %s where version=? AND pkgarch=?;" % (self.table), | ||
137 | (version, pkgarch)) | ||
138 | row = data.fetchone() | ||
139 | if row is not None: | ||
140 | return row[0] | ||
141 | else: | ||
142 | return 0 | ||
143 | |||
78 | try: | 144 | try: |
79 | self._execute("INSERT INTO %s VALUES (?, ?, ?, (select ifnull(max(value)+1,0) from %s where version=? AND pkgarch=?));" | 145 | self._execute("INSERT INTO %s VALUES (?, ?, ?, (select ifnull(max(value)+1, 0) from %s where version=? AND pkgarch=?));" |
80 | % (self.table,self.table), | 146 | % (self.table, self.table), |
81 | (version,pkgarch, checksum,version, pkgarch)) | 147 | (version, pkgarch, checksum, version, pkgarch)) |
82 | except sqlite3.IntegrityError as exc: | 148 | except sqlite3.IntegrityError as exc: |
83 | logger.error(str(exc)) | 149 | logger.error(str(exc)) |
84 | 150 | ||
@@ -92,10 +158,10 @@ class PRTable(object): | |||
92 | else: | 158 | else: |
93 | raise prserv.NotFoundError | 159 | raise prserv.NotFoundError |
94 | 160 | ||
95 | def _getValueNohist(self, version, pkgarch, checksum): | 161 | def _get_value_no_hist(self, version, pkgarch, checksum): |
96 | data=self._execute("SELECT value FROM %s \ | 162 | data=self._execute("SELECT value FROM %s \ |
97 | WHERE version=? AND pkgarch=? AND checksum=? AND \ | 163 | WHERE version=? AND pkgarch=? AND checksum=? AND \ |
98 | value >= (select max(value) from %s where version=? AND pkgarch=?);" | 164 | value >= (select max(value) from %s where version=? AND pkgarch=?);" |
99 | % (self.table, self.table), | 165 | % (self.table, self.table), |
100 | (version, pkgarch, checksum, version, pkgarch)) | 166 | (version, pkgarch, checksum, version, pkgarch)) |
101 | row=data.fetchone() | 167 | row=data.fetchone() |
@@ -103,9 +169,14 @@ class PRTable(object): | |||
103 | return row[0] | 169 | return row[0] |
104 | else: | 170 | else: |
105 | #no value found, try to insert | 171 | #no value found, try to insert |
172 | if self.read_only: | ||
173 | data = self._execute("SELECT ifnull(max(value)+1, 0) FROM %s where version=? AND pkgarch=?;" % (self.table), | ||
174 | (version, pkgarch)) | ||
175 | return data.fetchone()[0] | ||
176 | |||
106 | try: | 177 | try: |
107 | self._execute("INSERT OR REPLACE INTO %s VALUES (?, ?, ?, (select ifnull(max(value)+1,0) from %s where version=? AND pkgarch=?));" | 178 | self._execute("INSERT OR REPLACE INTO %s VALUES (?, ?, ?, (select ifnull(max(value)+1, 0) from %s where version=? AND pkgarch=?));" |
108 | % (self.table,self.table), | 179 | % (self.table, self.table), |
109 | (version, pkgarch, checksum, version, pkgarch)) | 180 | (version, pkgarch, checksum, version, pkgarch)) |
110 | except sqlite3.IntegrityError as exc: | 181 | except sqlite3.IntegrityError as exc: |
111 | logger.error(str(exc)) | 182 | logger.error(str(exc)) |
@@ -121,14 +192,17 @@ class PRTable(object): | |||
121 | else: | 192 | else: |
122 | raise prserv.NotFoundError | 193 | raise prserv.NotFoundError |
123 | 194 | ||
124 | def getValue(self, version, pkgarch, checksum): | 195 | def get_value(self, version, pkgarch, checksum): |
125 | if self.nohist: | 196 | if self.nohist: |
126 | return self._getValueNohist(version, pkgarch, checksum) | 197 | return self._get_value_no_hist(version, pkgarch, checksum) |
127 | else: | 198 | else: |
128 | return self._getValueHist(version, pkgarch, checksum) | 199 | return self._get_value_hist(version, pkgarch, checksum) |
129 | 200 | ||
130 | def _importHist(self, version, pkgarch, checksum, value): | 201 | def _import_hist(self, version, pkgarch, checksum, value): |
131 | val = None | 202 | if self.read_only: |
203 | return None | ||
204 | |||
205 | val = None | ||
132 | data = self._execute("SELECT value FROM %s WHERE version=? AND pkgarch=? AND checksum=?;" % self.table, | 206 | data = self._execute("SELECT value FROM %s WHERE version=? AND pkgarch=? AND checksum=?;" % self.table, |
133 | (version, pkgarch, checksum)) | 207 | (version, pkgarch, checksum)) |
134 | row = data.fetchone() | 208 | row = data.fetchone() |
@@ -151,24 +225,27 @@ class PRTable(object): | |||
151 | val = row[0] | 225 | val = row[0] |
152 | return val | 226 | return val |
153 | 227 | ||
154 | def _importNohist(self, version, pkgarch, checksum, value): | 228 | def _import_no_hist(self, version, pkgarch, checksum, value): |
229 | if self.read_only: | ||
230 | return None | ||
231 | |||
155 | try: | 232 | try: |
156 | #try to insert | 233 | #try to insert |
157 | self._execute("INSERT INTO %s VALUES (?, ?, ?, ?);" % (self.table), | 234 | self._execute("INSERT INTO %s VALUES (?, ?, ?, ?);" % (self.table), |
158 | (version, pkgarch, checksum,value)) | 235 | (version, pkgarch, checksum, value)) |
159 | except sqlite3.IntegrityError as exc: | 236 | except sqlite3.IntegrityError as exc: |
160 | #already have the record, try to update | 237 | #already have the record, try to update |
161 | try: | 238 | try: |
162 | self._execute("UPDATE %s SET value=? WHERE version=? AND pkgarch=? AND checksum=? AND value<?" | 239 | self._execute("UPDATE %s SET value=? WHERE version=? AND pkgarch=? AND checksum=? AND value<?" |
163 | % (self.table), | 240 | % (self.table), |
164 | (value,version,pkgarch,checksum,value)) | 241 | (value, version, pkgarch, checksum, value)) |
165 | except sqlite3.IntegrityError as exc: | 242 | except sqlite3.IntegrityError as exc: |
166 | logger.error(str(exc)) | 243 | logger.error(str(exc)) |
167 | 244 | ||
168 | self.dirty = True | 245 | self.dirty = True |
169 | 246 | ||
170 | data = self._execute("SELECT value FROM %s WHERE version=? AND pkgarch=? AND checksum=? AND value>=?;" % self.table, | 247 | data = self._execute("SELECT value FROM %s WHERE version=? AND pkgarch=? AND checksum=? AND value>=?;" % self.table, |
171 | (version,pkgarch,checksum,value)) | 248 | (version, pkgarch, checksum, value)) |
172 | row=data.fetchone() | 249 | row=data.fetchone() |
173 | if row is not None: | 250 | if row is not None: |
174 | return row[0] | 251 | return row[0] |
@@ -177,33 +254,33 @@ class PRTable(object): | |||
177 | 254 | ||
178 | def importone(self, version, pkgarch, checksum, value): | 255 | def importone(self, version, pkgarch, checksum, value): |
179 | if self.nohist: | 256 | if self.nohist: |
180 | return self._importNohist(version, pkgarch, checksum, value) | 257 | return self._import_no_hist(version, pkgarch, checksum, value) |
181 | else: | 258 | else: |
182 | return self._importHist(version, pkgarch, checksum, value) | 259 | return self._import_hist(version, pkgarch, checksum, value) |
183 | 260 | ||
184 | def export(self, version, pkgarch, checksum, colinfo): | 261 | def export(self, version, pkgarch, checksum, colinfo): |
185 | metainfo = {} | 262 | metainfo = {} |
186 | #column info | 263 | #column info |
187 | if colinfo: | 264 | if colinfo: |
188 | metainfo['tbl_name'] = self.table | 265 | metainfo["tbl_name"] = self.table |
189 | metainfo['core_ver'] = prserv.__version__ | 266 | metainfo["core_ver"] = prserv.__version__ |
190 | metainfo['col_info'] = [] | 267 | metainfo["col_info"] = [] |
191 | data = self._execute("PRAGMA table_info(%s);" % self.table) | 268 | data = self._execute("PRAGMA table_info(%s);" % self.table) |
192 | for row in data: | 269 | for row in data: |
193 | col = {} | 270 | col = {} |
194 | col['name'] = row['name'] | 271 | col["name"] = row["name"] |
195 | col['type'] = row['type'] | 272 | col["type"] = row["type"] |
196 | col['notnull'] = row['notnull'] | 273 | col["notnull"] = row["notnull"] |
197 | col['dflt_value'] = row['dflt_value'] | 274 | col["dflt_value"] = row["dflt_value"] |
198 | col['pk'] = row['pk'] | 275 | col["pk"] = row["pk"] |
199 | metainfo['col_info'].append(col) | 276 | metainfo["col_info"].append(col) |
200 | 277 | ||
201 | #data info | 278 | #data info |
202 | datainfo = [] | 279 | datainfo = [] |
203 | 280 | ||
204 | if self.nohist: | 281 | if self.nohist: |
205 | sqlstmt = "SELECT T1.version, T1.pkgarch, T1.checksum, T1.value FROM %s as T1, \ | 282 | sqlstmt = "SELECT T1.version, T1.pkgarch, T1.checksum, T1.value FROM %s as T1, \ |
206 | (SELECT version,pkgarch,max(value) as maxvalue FROM %s GROUP BY version,pkgarch) as T2 \ | 283 | (SELECT version, pkgarch, max(value) as maxvalue FROM %s GROUP BY version, pkgarch) as T2 \ |
207 | WHERE T1.version=T2.version AND T1.pkgarch=T2.pkgarch AND T1.value=T2.maxvalue " % (self.table, self.table) | 284 | WHERE T1.version=T2.version AND T1.pkgarch=T2.pkgarch AND T1.value=T2.maxvalue " % (self.table, self.table) |
208 | else: | 285 | else: |
209 | sqlstmt = "SELECT * FROM %s as T1 WHERE 1=1 " % self.table | 286 | sqlstmt = "SELECT * FROM %s as T1 WHERE 1=1 " % self.table |
@@ -226,12 +303,12 @@ class PRTable(object): | |||
226 | else: | 303 | else: |
227 | data = self._execute(sqlstmt) | 304 | data = self._execute(sqlstmt) |
228 | for row in data: | 305 | for row in data: |
229 | if row['version']: | 306 | if row["version"]: |
230 | col = {} | 307 | col = {} |
231 | col['version'] = row['version'] | 308 | col["version"] = row["version"] |
232 | col['pkgarch'] = row['pkgarch'] | 309 | col["pkgarch"] = row["pkgarch"] |
233 | col['checksum'] = row['checksum'] | 310 | col["checksum"] = row["checksum"] |
234 | col['value'] = row['value'] | 311 | col["value"] = row["value"] |
235 | datainfo.append(col) | 312 | datainfo.append(col) |
236 | return (metainfo, datainfo) | 313 | return (metainfo, datainfo) |
237 | 314 | ||
@@ -240,41 +317,45 @@ class PRTable(object): | |||
240 | for line in self.conn.iterdump(): | 317 | for line in self.conn.iterdump(): |
241 | writeCount = writeCount + len(line) + 1 | 318 | writeCount = writeCount + len(line) + 1 |
242 | fd.write(line) | 319 | fd.write(line) |
243 | fd.write('\n') | 320 | fd.write("\n") |
244 | return writeCount | 321 | return writeCount |
245 | 322 | ||
246 | class PRData(object): | 323 | class PRData(object): |
247 | """Object representing the PR database""" | 324 | """Object representing the PR database""" |
248 | def __init__(self, filename, nohist=True): | 325 | def __init__(self, filename, nohist=True, read_only=False): |
249 | self.filename=os.path.abspath(filename) | 326 | self.filename=os.path.abspath(filename) |
250 | self.nohist=nohist | 327 | self.nohist=nohist |
328 | self.read_only = read_only | ||
251 | #build directory hierarchy | 329 | #build directory hierarchy |
252 | try: | 330 | try: |
253 | os.makedirs(os.path.dirname(self.filename)) | 331 | os.makedirs(os.path.dirname(self.filename)) |
254 | except OSError as e: | 332 | except OSError as e: |
255 | if e.errno != errno.EEXIST: | 333 | if e.errno != errno.EEXIST: |
256 | raise e | 334 | raise e |
257 | self.connection=sqlite3.connect(self.filename, isolation_level="EXCLUSIVE", check_same_thread = False) | 335 | uri = "file:%s%s" % (self.filename, "?mode=ro" if self.read_only else "") |
336 | logger.debug("Opening PRServ database '%s'" % (uri)) | ||
337 | self.connection=sqlite3.connect(uri, uri=True, isolation_level="EXCLUSIVE", check_same_thread = False) | ||
258 | self.connection.row_factory=sqlite3.Row | 338 | self.connection.row_factory=sqlite3.Row |
259 | self.connection.execute("pragma synchronous = off;") | 339 | if not self.read_only: |
260 | self.connection.execute("PRAGMA journal_mode = MEMORY;") | 340 | self.connection.execute("pragma synchronous = off;") |
341 | self.connection.execute("PRAGMA journal_mode = MEMORY;") | ||
261 | self._tables={} | 342 | self._tables={} |
262 | 343 | ||
263 | def disconnect(self): | 344 | def disconnect(self): |
264 | self.connection.close() | 345 | self.connection.close() |
265 | 346 | ||
266 | def __getitem__(self,tblname): | 347 | def __getitem__(self, tblname): |
267 | if not isinstance(tblname, str): | 348 | if not isinstance(tblname, str): |
268 | raise TypeError("tblname argument must be a string, not '%s'" % | 349 | raise TypeError("tblname argument must be a string, not '%s'" % |
269 | type(tblname)) | 350 | type(tblname)) |
270 | if tblname in self._tables: | 351 | if tblname in self._tables: |
271 | return self._tables[tblname] | 352 | return self._tables[tblname] |
272 | else: | 353 | else: |
273 | tableobj = self._tables[tblname] = PRTable(self.connection, tblname, self.nohist) | 354 | tableobj = self._tables[tblname] = PRTable(self.connection, tblname, self.nohist, self.read_only) |
274 | return tableobj | 355 | return tableobj |
275 | 356 | ||
276 | def __delitem__(self, tblname): | 357 | def __delitem__(self, tblname): |
277 | if tblname in self._tables: | 358 | if tblname in self._tables: |
278 | del self._tables[tblname] | 359 | del self._tables[tblname] |
279 | logger.info("drop table %s" % (tblname)) | 360 | logger.info("drop table %s" % (tblname)) |
280 | self.connection.execute("DROP TABLE IF EXISTS %s;" % tblname) | 361 | self.connection.execute("DROP TABLE IF EXISTS %s;" % tblname) |