diff options
author | Joshua Watt <JPEWhacker@gmail.com> | 2021-10-07 14:32:00 -0500 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2021-10-11 11:00:06 +0100 |
commit | c7c47bb0d2c2263c4668c4269c669b282d6168d9 (patch) | |
tree | 19767cdfc5be31dbdef064439700891d091853f6 /bitbake/lib/hashserv/__init__.py | |
parent | ecb11a6848b4a86de3f04d7dcf12ce8ff6491a07 (diff) | |
download | poky-c7c47bb0d2c2263c4668c4269c669b282d6168d9.tar.gz |
bitbake: hashserv: Fix diverging report race condition
Fixes the hashequivalence server to resolve the diverging report race
error. This error occurs when the same task(hash) is run simultaneous on
two different builders, and then the results are reported back but the
hashes diverge (e.g. have different outhashes), and one outhash is
equivalent to a hash and another is not. If taskhash was not originally
in the database, the client will fallback to using the taskhash as the
suggested unihash and the server will see reports come in like:
taskhash: A
unihash: A
outhash: B
taskhash: C
unihash: C
outhash: B
taskhash: C
unihash: C
outhash: D
Note that the second and third reports are the same taskhash, with
diverging outhashes.
Taskhash C should be equivalent to taskhash (and unihash) A because they
share an outhash B, but the server would not do this when tasks were
reported in the order shown.
It became clear while trying to fix this that single large table to
store all reported hashes was going to make these updates difficult
since updating the unihash of all entries would be complex and time
consuming. Instead, it makes more sense to split apart the database into
two tables: One that maps taskhashes to unihashes and one that maps
outhashes to taskhashes. This should hopefully improve the parsing query
times as well since they only care about the taskhashes to unihashes
table, at the cost of more complex INNER JOIN queries on the lesser used
API.
Note this change does delete existing hash equivlance data and starts a
new database table rather than converting existing data.
(Bitbake rev: dff5a17558e2476064e85f35bad1fd65fec23600)
Signed-off-by: Joshua Watt <JPEWhacker@gmail.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/hashserv/__init__.py')
-rw-r--r-- | bitbake/lib/hashserv/__init__.py | 66 |
1 files changed, 44 insertions, 22 deletions
diff --git a/bitbake/lib/hashserv/__init__.py b/bitbake/lib/hashserv/__init__.py index 5f2e101e52..9cb3fd57a5 100644 --- a/bitbake/lib/hashserv/__init__.py +++ b/bitbake/lib/hashserv/__init__.py | |||
@@ -22,46 +22,68 @@ ADDR_TYPE_TCP = 1 | |||
22 | # is necessary | 22 | # is necessary |
23 | DEFAULT_MAX_CHUNK = 32 * 1024 | 23 | DEFAULT_MAX_CHUNK = 32 * 1024 |
24 | 24 | ||
25 | TABLE_DEFINITION = ( | 25 | UNIHASH_TABLE_DEFINITION = ( |
26 | ("method", "TEXT NOT NULL"), | 26 | ("method", "TEXT NOT NULL", "UNIQUE"), |
27 | ("outhash", "TEXT NOT NULL"), | 27 | ("taskhash", "TEXT NOT NULL", "UNIQUE"), |
28 | ("taskhash", "TEXT NOT NULL"), | 28 | ("unihash", "TEXT NOT NULL", ""), |
29 | ("unihash", "TEXT NOT NULL"), | 29 | ) |
30 | ("created", "DATETIME"), | 30 | |
31 | UNIHASH_TABLE_COLUMNS = tuple(name for name, _, _ in UNIHASH_TABLE_DEFINITION) | ||
32 | |||
33 | OUTHASH_TABLE_DEFINITION = ( | ||
34 | ("method", "TEXT NOT NULL", "UNIQUE"), | ||
35 | ("taskhash", "TEXT NOT NULL", "UNIQUE"), | ||
36 | ("outhash", "TEXT NOT NULL", "UNIQUE"), | ||
37 | ("created", "DATETIME", ""), | ||
31 | 38 | ||
32 | # Optional fields | 39 | # Optional fields |
33 | ("owner", "TEXT"), | 40 | ("owner", "TEXT", ""), |
34 | ("PN", "TEXT"), | 41 | ("PN", "TEXT", ""), |
35 | ("PV", "TEXT"), | 42 | ("PV", "TEXT", ""), |
36 | ("PR", "TEXT"), | 43 | ("PR", "TEXT", ""), |
37 | ("task", "TEXT"), | 44 | ("task", "TEXT", ""), |
38 | ("outhash_siginfo", "TEXT"), | 45 | ("outhash_siginfo", "TEXT", ""), |
39 | ) | 46 | ) |
40 | 47 | ||
41 | TABLE_COLUMNS = tuple(name for name, _ in TABLE_DEFINITION) | 48 | OUTHASH_TABLE_COLUMNS = tuple(name for name, _, _ in OUTHASH_TABLE_DEFINITION) |
49 | |||
50 | def _make_table(cursor, name, definition): | ||
51 | cursor.execute(''' | ||
52 | CREATE TABLE IF NOT EXISTS {name} ( | ||
53 | id INTEGER PRIMARY KEY AUTOINCREMENT, | ||
54 | {fields} | ||
55 | UNIQUE({unique}) | ||
56 | ) | ||
57 | '''.format( | ||
58 | name=name, | ||
59 | fields=" ".join("%s %s," % (name, typ) for name, typ, _ in definition), | ||
60 | unique=", ".join(name for name, _, flags in definition if "UNIQUE" in flags) | ||
61 | )) | ||
62 | |||
42 | 63 | ||
43 | def setup_database(database, sync=True): | 64 | def setup_database(database, sync=True): |
44 | db = sqlite3.connect(database) | 65 | db = sqlite3.connect(database) |
45 | db.row_factory = sqlite3.Row | 66 | db.row_factory = sqlite3.Row |
46 | 67 | ||
47 | with closing(db.cursor()) as cursor: | 68 | with closing(db.cursor()) as cursor: |
48 | cursor.execute(''' | 69 | _make_table(cursor, "unihashes_v2", UNIHASH_TABLE_DEFINITION) |
49 | CREATE TABLE IF NOT EXISTS tasks_v2 ( | 70 | _make_table(cursor, "outhashes_v2", OUTHASH_TABLE_DEFINITION) |
50 | id INTEGER PRIMARY KEY AUTOINCREMENT, | 71 | |
51 | %s | ||
52 | UNIQUE(method, outhash, taskhash) | ||
53 | ) | ||
54 | ''' % " ".join("%s %s," % (name, typ) for name, typ in TABLE_DEFINITION)) | ||
55 | cursor.execute('PRAGMA journal_mode = WAL') | 72 | cursor.execute('PRAGMA journal_mode = WAL') |
56 | cursor.execute('PRAGMA synchronous = %s' % ('NORMAL' if sync else 'OFF')) | 73 | cursor.execute('PRAGMA synchronous = %s' % ('NORMAL' if sync else 'OFF')) |
57 | 74 | ||
58 | # Drop old indexes | 75 | # Drop old indexes |
59 | cursor.execute('DROP INDEX IF EXISTS taskhash_lookup') | 76 | cursor.execute('DROP INDEX IF EXISTS taskhash_lookup') |
60 | cursor.execute('DROP INDEX IF EXISTS outhash_lookup') | 77 | cursor.execute('DROP INDEX IF EXISTS outhash_lookup') |
78 | cursor.execute('DROP INDEX IF EXISTS taskhash_lookup_v2') | ||
79 | cursor.execute('DROP INDEX IF EXISTS outhash_lookup_v2') | ||
80 | |||
81 | # TODO: Upgrade from tasks_v2? | ||
82 | cursor.execute('DROP TABLE IF EXISTS tasks_v2') | ||
61 | 83 | ||
62 | # Create new indexes | 84 | # Create new indexes |
63 | cursor.execute('CREATE INDEX IF NOT EXISTS taskhash_lookup_v2 ON tasks_v2 (method, taskhash, created)') | 85 | cursor.execute('CREATE INDEX IF NOT EXISTS taskhash_lookup_v3 ON unihashes_v2 (method, taskhash)') |
64 | cursor.execute('CREATE INDEX IF NOT EXISTS outhash_lookup_v2 ON tasks_v2 (method, outhash)') | 86 | cursor.execute('CREATE INDEX IF NOT EXISTS outhash_lookup_v3 ON outhashes_v2 (method, outhash)') |
65 | 87 | ||
66 | return db | 88 | return db |
67 | 89 | ||