summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/prserv/db.py
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/prserv/db.py')
-rw-r--r--bitbake/lib/prserv/db.py193
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
32class PRTable(object): 34class 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
246class PRData(object): 323class 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)