From: Patrick Donnelly Date: Wed, 17 Apr 2024 19:52:36 +0000 (-0400) Subject: pybind/mgr: disable sqlite3/python autocommit X-Git-Tag: v18.2.5~46^2~1 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=ad0266f3a46bce56581a1e71958be975a06d2969;p=ceph.git pybind/mgr: disable sqlite3/python autocommit SQLite3 and python's binding were both committing transactions at unintended points. Turn it off and stop using executescript. Fixes: https://tracker.ceph.com/issues/65494 Signed-off-by: Patrick Donnelly (cherry picked from commit 6eacfe96625e272fdb9094ab8753e70ec163c04d) --- diff --git a/src/pybind/mgr/devicehealth/module.py b/src/pybind/mgr/devicehealth/module.py index e4356175c6a42..e90db88fd1695 100644 --- a/src/pybind/mgr/devicehealth/module.py +++ b/src/pybind/mgr/devicehealth/module.py @@ -50,31 +50,39 @@ def get_nvme_wear_level(data: Dict[Any, Any]) -> Optional[float]: class Module(MgrModule): # latest (if db does not exist) - SCHEMA = """ -CREATE TABLE Device ( - devid TEXT PRIMARY KEY -) WITHOUT ROWID; -CREATE TABLE DeviceHealthMetrics ( - time DATETIME DEFAULT (strftime('%s', 'now')), - devid TEXT NOT NULL REFERENCES Device (devid), - raw_smart TEXT NOT NULL, - PRIMARY KEY (time, devid) -); -""" + SCHEMA = [ + """ + CREATE TABLE Device ( + devid TEXT PRIMARY KEY + ) WITHOUT ROWID; + """, + """ + CREATE TABLE DeviceHealthMetrics ( + time DATETIME DEFAULT (strftime('%s', 'now')), + devid TEXT NOT NULL REFERENCES Device (devid), + raw_smart TEXT NOT NULL, + PRIMARY KEY (time, devid) + ); + """ + ] SCHEMA_VERSIONED = [ # v1 - """ -CREATE TABLE Device ( - devid TEXT PRIMARY KEY -) WITHOUT ROWID; -CREATE TABLE DeviceHealthMetrics ( - time DATETIME DEFAULT (strftime('%s', 'now')), - devid TEXT NOT NULL REFERENCES Device (devid), - raw_smart TEXT NOT NULL, - PRIMARY KEY (time, devid) -); -""" + [ + """ + CREATE TABLE Device ( + devid TEXT PRIMARY KEY + ) WITHOUT ROWID; + """, + """ + CREATE TABLE DeviceHealthMetrics ( + time DATETIME DEFAULT (strftime('%s', 'now')), + devid TEXT NOT NULL REFERENCES Device (devid), + raw_smart TEXT NOT NULL, + PRIMARY KEY (time, devid) + ); + """, + ] ] MODULE_OPTIONS = [ @@ -320,6 +328,7 @@ CREATE TABLE DeviceHealthMetrics ( done = False with ioctx, self._db_lock, self.db: + self.db.execute('BEGIN;') count = 0 for obj in ioctx.list_objects(): try: @@ -512,6 +521,7 @@ CREATE TABLE DeviceHealthMetrics ( """ with self._db_lock, self.db: + self.db.execute('BEGIN;') self._create_device(devid) self.db.execute(SQL, (devid, json.dumps(data))) self._prune_device_metrics() @@ -566,6 +576,7 @@ CREATE TABLE DeviceHealthMetrics ( self.log.debug(f"_get_device_metrics: {devid} {sample} {min_sample}") with self._db_lock, self.db: + self.db.execute('BEGIN;') if isample: cursor = self.db.execute(SQL_EXACT, (devid, isample)) else: diff --git a/src/pybind/mgr/mgr_module.py b/src/pybind/mgr/mgr_module.py index aa05ba9602bcd..93c4458ea4284 100644 --- a/src/pybind/mgr/mgr_module.py +++ b/src/pybind/mgr/mgr_module.py @@ -979,8 +979,8 @@ class MgrModule(ceph_module.BaseMgrModule, MgrModuleLoggingMixin): MODULE_OPTION_DEFAULTS = {} # type: Dict[str, Any] # Database Schema - SCHEMA = None # type: Optional[str] - SCHEMA_VERSIONED = None # type: Optional[List[str]] + SCHEMA = None # type: Optional[List[str]] + SCHEMA_VERSIONED = None # type: Optional[List[List[str]]] # Priority definitions for perf counters PRIO_CRITICAL = 10 @@ -1168,15 +1168,20 @@ class MgrModule(ceph_module.BaseMgrModule, MgrModuleLoggingMixin): self.appify_pool(self.MGR_POOL_NAME, 'mgr') def create_skeleton_schema(self, db: sqlite3.Connection) -> None: - SQL = """ + SQL = [ + """ CREATE TABLE IF NOT EXISTS MgrModuleKV ( key TEXT PRIMARY KEY, value NOT NULL ) WITHOUT ROWID; - INSERT OR IGNORE INTO MgrModuleKV (key, value) VALUES ('__version', 0); + """, """ + INSERT OR IGNORE INTO MgrModuleKV (key, value) VALUES ('__version', 0); + """, + ] - db.executescript(SQL) + for sql in SQL: + db.execute(sql) def update_schema_version(self, db: sqlite3.Connection, version: int) -> None: SQL = "UPDATE OR ROLLBACK MgrModuleKV SET value = ? WHERE key = '__version';" @@ -1215,7 +1220,8 @@ class MgrModule(ceph_module.BaseMgrModule, MgrModuleLoggingMixin): if version <= 0: self.log.info(f"creating main.db for {self.module_name}") assert self.SCHEMA is not None - db.executescript(self.SCHEMA) + for sql in self.SCHEMA: + db.execute(sql) self.update_schema_version(db, 1) else: assert self.SCHEMA_VERSIONED is not None @@ -1224,8 +1230,8 @@ class MgrModule(ceph_module.BaseMgrModule, MgrModuleLoggingMixin): raise RuntimeError(f"main.db version is newer ({version}) than module ({latest})") for i in range(version, latest): self.log.info(f"upgrading main.db for {self.module_name} from {i-1}:{i}") - SQL = self.SCHEMA_VERSIONED[i] - db.executescript(SQL) + for sql in self.SCHEMA_VERSIONED[i]: + db.execute(sql) if version < latest: self.update_schema_version(db, latest) @@ -1236,6 +1242,7 @@ class MgrModule(ceph_module.BaseMgrModule, MgrModuleLoggingMixin): kv = self.get_module_option('sqlite3_killpoint') with db: + db.execute('BEGIN;') self.create_skeleton_schema(db) if kv == 1: os._exit(120) @@ -1271,7 +1278,10 @@ class MgrModule(ceph_module.BaseMgrModule, MgrModuleLoggingMixin): self.create_mgr_pool() uri = f"file:///{self.MGR_POOL_NAME}:{self.module_name}/main.db?vfs=ceph"; self.log.debug(f"using uri {uri}") - db = sqlite3.connect(uri, check_same_thread=False, uri=True) + try: + db = sqlite3.connect(uri, check_same_thread=False, uri=True, autocommit=False) # type: ignore[call-arg] + except TypeError: + db = sqlite3.connect(uri, check_same_thread=False, uri=True, isolation_level=None) # if libcephsqlite reconnects, update the addrv for blocklist with db: cur = db.execute('SELECT json_extract(ceph_status(), "$.addr");')