|
KiCad PCB EDA Suite
|
Reads a Microsoft Access database (.mdb or .accdb) through ADO and the ACE OLE DB provider, read only and shared, so the file can stay open in Access. More...
#include <ace_backend.h>
Classes | |
| struct | CYCLE_SESSION |
| A session opened for one load cycle, and the tables it has read, which it never reads again. More... | |
| struct | PASS_DIGEST |
| What one complete pass over a table returned, as a verified read compares it. More... | |
Public Types | |
| enum class | PROVIDER_STATE { AVAILABLE , MISSING , PENDING , BUSY } |
Public Member Functions | |
| ACE_BACKEND (std::string aPath, std::string aPassword, int aTimeoutSeconds) | |
| ~ACE_BACKEND () override | |
| bool | Connect () override |
| void | Disconnect () override |
| bool | IsConnected () const override |
| bool | ListTables (std::vector< std::string > &aTables) override |
| Lists the tables and views, sorted by name. | |
| std::optional< DB_TABLE_INFO > | DescribeTable (const std::string &aTable) override |
| bool | ReadTable (const DB_TABLE_INFO &aTable, const std::vector< std::string > &aColumns, size_t aMaxRows, std::vector< std::string > &aLabels, const DB_ROW_SINK &aSink) override |
| Reads rows of a table, handing each to aSink. | |
| bool | ReadAllRows (const DB_TABLE_INFO &aTable, const std::vector< std::string > &aColumns, std::vector< std::string > &aLabels, const DB_ROW_SINK &aSink, const DB_RESTART_SINK &aRestart) override |
| A verified read. | |
| void | BeginLoadCycle (const DB_STOP_CHECK &aStopped) override |
| Brackets a load cycle, in which the caller reads each table once. | |
| void | EndLoadCycle () override |
| Closes the sessions the cycle opened, on the worker thread. | |
| std::string | GetLastError () const override |
| DB_FAILURE | GetLastFailure () const override |
| virtual bool | ListColumns (const std::string &aTable, std::vector< std::string > &aColumns) |
| Lists the column names of a table as the catalog reports them, empty if it has none, false if the catalog failed. | |
| virtual std::optional< bool > | ReadRow (const DB_TABLE_INFO &aTable, const std::vector< std::string > &aColumns, const std::string &aKeyColumn, const std::string &aKey, std::vector< std::string > &aLabels, std::vector< DB_VALUE > &aRow) |
| Reads the one row whose key column equals aKey, using an indexed lookup if the backend has one. | |
Static Public Member Functions | |
| static PROVIDER_STATE | ProviderState () |
| Tells whether the ACE OLE DB provider is installed and loads. | |
| static std::string | ProviderPendingMessage () |
| The message for a source whose provider check has not finished. | |
| static std::string | ProviderMissingMessage () |
| The message for a source that needs the provider when ProviderState() is MISSING. | |
| static DB_BACKEND_RESULT | Create (const DATABASE_SOURCE &aSource, const wxString &aBasePath) |
| Builds the backend for a source. | |
Static Public Attributes | |
| static constexpr size_t | ALL_ROWS = std::numeric_limits<size_t>::max() |
| Passed as ReadTable()'s row limit to read every row. | |
Private Member Functions | |
| std::optional< PASS_DIGEST > | readPass (uint64_t aSession, const std::string &aSql, const std::string &aUnorderedSql, size_t aMaxRows, std::vector< std::string > &aLabels, const DB_ROW_SINK *aSink, std::optional< ACE_ENGINE_OP::CLOCK::time_point > aDeadline=std::nullopt) |
| Runs one pass of aSql on aSession, recording a failure as the backend's. | |
| std::optional< uint64_t > | freshSession (const std::string &aTable, ACE_ENGINE_OP::CLOCK::time_point aDeadline, const std::function< bool()> &aMayStart) |
| A session of the cycle that has not read aTable, now marked as having read it, or nullopt if one could not open before aDeadline. | |
| bool | closeSpentSessions (ACE_ENGINE_OP::CLOCK::time_point aDeadline) |
| Closes the oldest sessions of the cycle, which have all read the current table, so that one more fits. | |
| bool | cycleStopped () const |
| bool | pauseUnlessStopped (std::chrono::milliseconds aWait) |
| Sleeps for aWait; false if the cycle's stop check came true first. | |
| void | failStopped (const std::string &aTable) |
| bool | readVerified (const DB_TABLE_INFO &aTable, const std::vector< std::string > &aColumns, std::vector< std::string > &aLabels, const DB_ROW_SINK &aSink, const DB_RESTART_SINK &aRestart) |
| The verified read itself, inside a load cycle. | |
| template<typename R> | |
| std::optional< R > | runOnWorker (std::function< R(DB_JOB_CONTEXT &)> aJob, const DB_ROW_SINK *aSink, std::shared_ptr< ACE_ENGINE_OP > aOp=nullptr, std::optional< std::chrono::milliseconds > aProgressBound=std::nullopt) |
| Runs aJob on the worker, recording why it did not finish as the failure. | |
| void | dropConnection (std::shared_ptr< ACE_ENGINE_OP > aOp=nullptr, bool aForExit=false) |
| Forgets the connection and the cycle's sessions and closes them on the worker thread, never on the caller. | |
| bool | closeOnWorker (std::vector< uint64_t > aIds, std::shared_ptr< ACE_ENGINE_OP > aOp, std::optional< std::chrono::milliseconds > aBound=std::nullopt) |
| Closes aIds on the worker thread under aOp, recording a close that lost the engine lock; false if the wait for the worker, aBound or else what is left of aOp, expired. | |
| void | fail (DB_FAILURE aFailure, std::string aError) |
| std::shared_ptr< ACE_ENGINE_OP > | newOp () const |
| void | failCall (DB_FAILURE aFailure, std::string aMessage) |
| Records a failure of a call that ran, and drops the connection if the failure means it cannot be trusted. | |
| bool | requireConnection () |
| Fails with a message and returns false unless a connection is open. | |
Private Attributes | |
| std::string | m_path |
| std::string | m_password |
| int | m_timeout |
| std::shared_ptr< ACE_ENGINE_OP > | m_lastOp |
| The operation the caller last ran, which a failure that drops the connection continues. | |
| std::unique_ptr< DB_WORKER_THREAD > | m_worker |
| uint64_t | m_session = 0 |
| Names this backend's connection among those the worker thread holds. | |
| std::wstring | m_progId |
| The provider that opened the connection, which the cycle's sessions use too. | |
| std::vector< CYCLE_SESSION > | m_cycleSessions |
| DB_STOP_CHECK | m_cycleStop |
| Set by the outermost load cycle, which a verified read checks before every open and pass. | |
| int | m_cycleDepth = 0 |
| How many load cycles are open; the sessions are closed when the last one ends. | |
| std::atomic< bool > | m_connected { false } |
| std::string | m_lastError |
| DB_FAILURE | m_lastFailure = DB_FAILURE::UNKNOWN |
Static Private Attributes | |
| static constexpr size_t | MAX_CYCLE_SESSIONS = 2 |
| The most sessions a load cycle holds at once. | |
Reads a Microsoft Access database (.mdb or .accdb) through ADO and the ACE OLE DB provider, read only and shared, so the file can stay open in Access.
Every COM object lives on the worker thread, an apartment of its own, so a file on a share that stopped answering costs the caller a bounded wait and not a hung program. The provider cannot cancel a read that is blocked on file I/O, so such a thread is detached and finishes when the operating system gives up on the share.
Definition at line 79 of file ace_backend.h.
|
strong |
| Enumerator | |
|---|---|
| AVAILABLE | |
| MISSING | |
| PENDING | The check has not finished, so nothing is known yet. |
| BUSY | The check could not start because the engine lock stayed out of reach. |
Definition at line 139 of file ace_backend.h.
| ACE_BACKEND::ACE_BACKEND | ( | std::string | aPath, |
| std::string | aPassword, | ||
| int | aTimeoutSeconds ) |
| aPath | the database file, as UTF-8 |
| aPassword | the database password, empty if the file has none; never appears in a message or trace |
| aTimeoutSeconds | the provider's connection and command timeout, zero for its default; a call waits on the worker without progress for at most this plus 10 s, or 30 s when it is zero, and the provider probe of a first connect may add up to 10 s |
Definition at line 1590 of file ace_backend.cpp.
References m_password, m_path, m_timeout, m_worker, MarkAccessWorkerAbandoned(), and move.
|
override |
Definition at line 1606 of file ace_backend.cpp.
References dropConnection(), m_path, m_worker, newOp(), and traceDatabase.
|
overridevirtual |
Brackets a load cycle, in which the caller reads each table once.
A backend may keep what it opens for the cycle's reads until the cycle ends. Cycles may nest, and only the outermost begin and end count. Nesting is backend-wide and may cross threads, as when a lookup on one thread reads a table while a refresh on another has a cycle open. The nested read keeps the stop check and sessions of the outermost cycle.
| aStopped | may be empty; a backend that retries a read gives up when it returns true |
Reimplemented from DATABASE_BACKEND.
Definition at line 2039 of file ace_backend.cpp.
References m_cycleDepth, and m_cycleStop.
Referenced by ReadAllRows().
|
private |
Closes aIds on the worker thread under aOp, recording a close that lost the engine lock; false if the wait for the worker, aBound or else what is left of aOp, expired.
Definition at line 1797 of file ace_backend.cpp.
References AccessEngineBusyMessage(), ACE_ENGINE_OP::EXPIRED, fail(), m_worker, and TIMEOUT.
Referenced by closeSpentSessions(), dropConnection(), and EndLoadCycle().
|
private |
Closes the oldest sessions of the cycle, which have all read the current table, so that one more fits.
Definition at line 2107 of file ace_backend.cpp.
References DB_WORKER_THREAD::CallerBound(), closeOnWorker(), DescribeWorkerOutcome(), fail(), DB_WORKER_FAILURE::failure, m_connected, m_cycleSessions, m_lastError, m_path, m_session, m_timeout, m_worker, MAX_CYCLE_SESSIONS, and DB_WORKER_FAILURE::message.
Referenced by freshSession().
|
overridevirtual |
Implements DATABASE_BACKEND.
Definition at line 1819 of file ace_backend.cpp.
References _, AccessEngineBusyMessage(), AVAILABLE, BUSY, describeFailure(), fail(), FILE_NOT_FOUND, m_connected, m_lastError, m_lastFailure, m_password, m_path, m_progId, m_session, m_timeout, MISSING, newOp(), path, PENDING, PROVIDER_MISSING, ProviderMissingMessage(), ProviderPendingMessage(), result, runOnWorker(), TIMEOUT, UNKNOWN, and utf8().
|
staticinherited |
Builds the backend for a source.
| aSource | the source as configured; ${CWD} is expanded in its connection string and path |
| aBasePath | the directory ${CWD} stands for |
Definition at line 34 of file database_backend.cpp.
References _, ACCESS, DATABASE_SOURCE::Expanded(), INVALID, INVALID_TYPE, ACE_BACKEND::MISSING, NOT_SUPPORTED_ON_PLATFORM, ODBC, PROVIDER_MISSING, ACE_BACKEND::ProviderMissingMessage(), ACE_BACKEND::ProviderState(), source, SQLITE, UNKNOWN, and utf8().
Referenced by SCH_IO_DATABASE::connectOnce(), and SCH_IO_DATABASE::CreateConnection().
|
private |
Definition at line 2075 of file ace_backend.cpp.
References m_cycleStop.
Referenced by pauseUnlessStopped(), and readVerified().
|
overridevirtual |
Implements DATABASE_BACKEND.
Definition at line 1917 of file ace_backend.cpp.
References describeFailure(), failCall(), info, m_lastError, m_lastFailure, m_password, m_path, m_session, requireConnection(), result, runOnWorker(), and UNKNOWN.
|
overridevirtual |
Implements DATABASE_BACKEND.
Definition at line 1879 of file ace_backend.cpp.
References dropConnection().
|
private |
Forgets the connection and the cycle's sessions and closes them on the worker thread, never on the caller.
A live worker also learns the operation for its exit hook when aForExit is set, even with no connection to close. An abandoned or absent worker is left alone, since its sessions are not reachable from another thread.
Definition at line 1771 of file ace_backend.cpp.
References closeOnWorker(), m_connected, m_cycleSessions, m_session, m_worker, and newOp().
Referenced by Disconnect(), failCall(), runOnWorker(), and ~ACE_BACKEND().
|
overridevirtual |
Closes the sessions the cycle opened, on the worker thread.
Reimplemented from DATABASE_BACKEND.
Definition at line 2047 of file ace_backend.cpp.
References closeOnWorker(), m_connected, m_cycleDepth, m_cycleSessions, m_cycleStop, m_session, and newOp().
Referenced by ReadAllRows().
|
private |
Definition at line 1651 of file ace_backend.cpp.
References m_lastError, m_lastFailure, m_password, ScrubSecret(), and traceDatabase.
Referenced by closeOnWorker(), closeSpentSessions(), Connect(), failCall(), failStopped(), readPass(), readVerified(), requireConnection(), and runOnWorker().
|
private |
Records a failure of a call that ran, and drops the connection if the failure means it cannot be trusted.
Definition at line 1706 of file ace_backend.cpp.
References dropConnection(), fail(), invalidates(), and m_lastOp.
Referenced by DescribeTable(), freshSession(), ListTables(), and readPass().
|
private |
Definition at line 2081 of file ace_backend.cpp.
References _, fail(), UNKNOWN, and utf8().
Referenced by readVerified().
|
private |
A session of the cycle that has not read aTable, now marked as having read it, or nullopt if one could not open before aDeadline.
An open the file's lock refuses is tried again after a growing pause. No open starts unless aMayStart, which records its own failure, allows it.
Definition at line 2144 of file ace_backend.cpp.
References DB_WORKER_THREAD::CallerBound(), closeSpentSessions(), describeFailure(), failCall(), FILE_IN_USE, FileInUseBackoff(), m_cycleSessions, m_password, m_path, m_progId, m_timeout, path, pauseUnlessStopped(), result, runOnWorker(), and traceDatabase.
Referenced by readVerified().
|
inlineoverridevirtual |
|
inlineoverridevirtual |
Implements DATABASE_BACKEND.
Definition at line 137 of file ace_backend.h.
References m_lastFailure.
|
inlineoverridevirtual |
|
virtualinherited |
Lists the column names of a table as the catalog reports them, empty if it has none, false if the catalog failed.
Reimplemented in ODBC_BACKEND.
Definition at line 71 of file database_backend.cpp.
References DescribeTable(), GetLastError(), info, and DB_COLUMN::name.
|
overridevirtual |
Lists the tables and views, sorted by name.
Implements DATABASE_BACKEND.
Definition at line 1885 of file ace_backend.cpp.
References describeFailure(), failCall(), m_lastError, m_password, m_path, m_session, requireConnection(), result, and runOnWorker().
|
private |
Definition at line 1600 of file ace_backend.cpp.
References DB_WORKER_THREAD::CallerBound(), and m_timeout.
Referenced by Connect(), dropConnection(), EndLoadCycle(), runOnWorker(), and ~ACE_BACKEND().
|
private |
Sleeps for aWait; false if the cycle's stop check came true first.
Definition at line 2088 of file ace_backend.cpp.
References cycleStopped(), and left.
Referenced by freshSession(), and readVerified().
|
static |
The message for a source that needs the provider when ProviderState() is MISSING.
Definition at line 1637 of file ace_backend.cpp.
References _, message, and utf8().
Referenced by Connect(), DATABASE_BACKEND::Create(), and describeFailure().
|
static |
The message for a source whose provider check has not finished.
Definition at line 1631 of file ace_backend.cpp.
Referenced by Connect().
|
static |
Tells whether the ACE OLE DB provider is installed and loads.
The check runs on first use, on a COM thread of its own, and a finished answer is kept for the life of the process. This does not wait, so a check still running reports PENDING and Connect() is the one place that waits for it. Nothing calls this at startup.
Definition at line 1623 of file ace_backend.cpp.
Referenced by accessProvider(), and DATABASE_BACKEND::Create().
|
overridevirtual |
A verified read.
Every pass runs on a session of the load cycle that has not read the table, since a session keeps serving the pages it read for seconds after another user changed them; a session is opened when none is left, and the cycle keeps at most two. The first pass only hashes the rows. Every later pass streams its rows to aSink and hashes them, and is compared with the pass before it. A pass that disagrees is followed by aRestart and another pass after a pause of 50 to 250 ms. The first two passes always run. No retry starts once the caller's bound, counted from the end of the second pass, has passed, and no open or pass starts once the cycle's stop check is true; the read then fails, as FILE_IN_USE if the bound ran out, and delivers nothing that may be kept. A read outside a load cycle runs in a cycle of its own.
A running open or pass is bounded only by the worker's progress bound, so a live read of a slow share is never cut short. Its wait for the engine lock ends a bound after it started, or for a retry when the bound runs out.
A table is published only when two consecutive complete passes, on two sessions that had not read the table before, returned identical content (row count, column names and an ordered hash over every column). The published table then equals the table's state at one instant between the passes, provided that (a) no row returns to an earlier value between the passes, (b) no single writer commit takes longer than a pass to become fully visible, and (c) neither session serves a page older than the other pass's read of it. This detects disagreement; it does not certify transactional consistency. There is no cross-table consistency.
Reimplemented from DATABASE_BACKEND.
Definition at line 2202 of file ace_backend.cpp.
References BeginLoadCycle(), EndLoadCycle(), m_lastError, m_lastFailure, readVerified(), and requireConnection().
|
private |
Runs one pass of aSql on aSession, recording a failure as the backend's.
| aSink | receives the rows; null only hashes them |
| aDeadline | is a verified read's deadline for the engine lock, which leaves the pass bounded by progress |
Definition at line 1992 of file ace_backend.cpp.
References DB_WORKER_THREAD::CallerBound(), describeFailure(), fail(), failCall(), DB_READ_DELIVERY::Finish(), DB_READ_DELIVERY::Labels(), m_password, m_path, m_timeout, result, runOnWorker(), DB_READ_DELIVERY::Sink(), DB_READ_DELIVERY::SinkFailureMessage(), DB_READ_DELIVERY::SinkThrew(), and UNKNOWN.
Referenced by ReadTable(), and readVerified().
|
inlinevirtualinherited |
Reads the one row whose key column equals aKey, using an indexed lookup if the backend has one.
Reimplemented in ODBC_BACKEND.
Definition at line 170 of file database_backend.h.
|
overridevirtual |
Reads rows of a table, handing each to aSink.
| aColumns | the columns to read; empty reads all of them |
| aMaxRows | stops after this many rows; zero fills aLabels and fetches no rows. A bounded read is ordered by the first column where the backend can. |
| aLabels | is filled with the result-column labels as the source spells them, before the first call to aSink |
Implements DATABASE_BACKEND.
Definition at line 1956 of file ace_backend.cpp.
References DATABASE_BACKEND::ALL_ROWS, m_lastError, m_session, DB_TABLE_INFO::name, readPass(), requireConnection(), and top().
|
private |
The verified read itself, inside a load cycle.
Definition at line 2233 of file ace_backend.cpp.
References _, DATABASE_BACKEND::ALL_ROWS, DB_WORKER_THREAD::CallerBound(), cycleStopped(), fail(), failStopped(), FILE_IN_USE, freshSession(), m_path, m_timeout, MS, DB_TABLE_INFO::name, path, pauseUnlessStopped(), readPass(), table, traceDatabase, and utf8().
Referenced by ReadAllRows().
|
private |
Fails with a message and returns false unless a connection is open.
Definition at line 1715 of file ace_backend.cpp.
References _, fail(), m_connected, UNKNOWN, and utf8().
Referenced by DescribeTable(), ListTables(), ReadAllRows(), and ReadTable().
|
private |
Runs aJob on the worker, recording why it did not finish as the failure.
Definition at line 1726 of file ace_backend.cpp.
References AccessEngineBusyMessage(), DB_WORKER_FAILURE::connection, DescribeWorkerOutcome(), DB_WORKER_FAILURE::DROP, dropConnection(), fail(), DB_WORKER_FAILURE::failure, DB_WORKER_FAILURE::FORGET, m_connected, m_cycleSessions, m_lastOp, m_path, m_session, m_worker, DB_WORKER_FAILURE::message, newOp(), result, and TIMEOUT.
Referenced by Connect(), DescribeTable(), freshSession(), ListTables(), and readPass().
|
staticconstexprinherited |
Passed as ReadTable()'s row limit to read every row.
Definition at line 106 of file database_backend.h.
Referenced by ReadAllRows(), ACE_BACKEND::ReadTable(), ODBC_BACKEND::ReadTable(), SQLITE_BACKEND::ReadTable(), and ACE_BACKEND::readVerified().
|
private |
Definition at line 266 of file ace_backend.h.
Referenced by closeSpentSessions(), Connect(), dropConnection(), EndLoadCycle(), IsConnected(), requireConnection(), and runOnWorker().
|
private |
How many load cycles are open; the sessions are closed when the last one ends.
Definition at line 264 of file ace_backend.h.
Referenced by BeginLoadCycle(), and EndLoadCycle().
|
private |
Definition at line 258 of file ace_backend.h.
Referenced by closeSpentSessions(), dropConnection(), EndLoadCycle(), freshSession(), and runOnWorker().
|
private |
Set by the outermost load cycle, which a verified read checks before every open and pass.
Definition at line 261 of file ace_backend.h.
Referenced by BeginLoadCycle(), cycleStopped(), and EndLoadCycle().
|
private |
Definition at line 268 of file ace_backend.h.
Referenced by closeSpentSessions(), Connect(), DescribeTable(), fail(), GetLastError(), ListTables(), ReadAllRows(), and ReadTable().
|
private |
Definition at line 269 of file ace_backend.h.
Referenced by Connect(), DescribeTable(), fail(), GetLastFailure(), and ReadAllRows().
|
private |
The operation the caller last ran, which a failure that drops the connection continues.
Definition at line 245 of file ace_backend.h.
Referenced by failCall(), and runOnWorker().
|
private |
Definition at line 241 of file ace_backend.h.
Referenced by ACE_BACKEND(), Connect(), DescribeTable(), fail(), freshSession(), ListTables(), and readPass().
|
private |
Definition at line 240 of file ace_backend.h.
Referenced by ACE_BACKEND(), closeSpentSessions(), Connect(), DescribeTable(), freshSession(), ListTables(), readPass(), readVerified(), runOnWorker(), and ~ACE_BACKEND().
|
private |
The provider that opened the connection, which the cycle's sessions use too.
Definition at line 253 of file ace_backend.h.
Referenced by Connect(), and freshSession().
|
private |
Names this backend's connection among those the worker thread holds.
Definition at line 250 of file ace_backend.h.
Referenced by closeSpentSessions(), Connect(), DescribeTable(), dropConnection(), EndLoadCycle(), ListTables(), ReadTable(), and runOnWorker().
|
private |
Definition at line 242 of file ace_backend.h.
Referenced by ACE_BACKEND(), closeSpentSessions(), Connect(), freshSession(), newOp(), readPass(), and readVerified().
|
private |
Definition at line 247 of file ace_backend.h.
Referenced by ACE_BACKEND(), closeOnWorker(), closeSpentSessions(), dropConnection(), runOnWorker(), and ~ACE_BACKEND().
|
staticconstexprprivate |
The most sessions a load cycle holds at once.
Definition at line 256 of file ace_backend.h.
Referenced by closeSpentSessions().