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