KiCad PCB EDA Suite
Loading...
Searching...
No Matches
ace_backend.h
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#ifndef KICAD_ACE_BACKEND_H
21#define KICAD_ACE_BACKEND_H
22
23#include <atomic>
24#include <chrono>
25#include <cstdint>
26#include <functional>
27#include <memory>
28#include <optional>
29#include <set>
30#include <string>
31#include <vector>
32
34
35#include "db_worker_thread.h"
36
37
44{
45 using CLOCK = std::chrono::steady_clock;
46
47 enum class STATE
48 {
53 };
54
55 explicit ACE_ENGINE_OP( CLOCK::time_point aDeadline ) :
56 deadline( aDeadline )
57 {
58 }
59
61 bool Busy() const
62 {
63 const STATE current = state;
64 return current == STATE::WAITING || current == STATE::EXPIRED;
65 }
66
67 const CLOCK::time_point deadline;
68 std::atomic<STATE> state{ STATE::IDLE };
69};
70
71
80{
81public:
89 ACE_BACKEND( std::string aPath, std::string aPassword, int aTimeoutSeconds );
90
91 ~ACE_BACKEND() override;
92
93 bool Connect() override;
94
95 void Disconnect() override;
96
97 bool IsConnected() const override { return m_connected; }
98
99 bool ListTables( std::vector<std::string>& aTables ) override;
100
101 std::optional<DB_TABLE_INFO> DescribeTable( const std::string& aTable ) override;
102
103 bool ReadTable( const DB_TABLE_INFO& aTable, const std::vector<std::string>& aColumns, size_t aMaxRows,
104 std::vector<std::string>& aLabels, const DB_ROW_SINK& aSink ) override;
105
126 bool ReadAllRows( const DB_TABLE_INFO& aTable, const std::vector<std::string>& aColumns,
127 std::vector<std::string>& aLabels, const DB_ROW_SINK& aSink,
128 const DB_RESTART_SINK& aRestart ) override;
129
130 void BeginLoadCycle( const DB_STOP_CHECK& aStopped ) override;
131
133 void EndLoadCycle() override;
134
135 std::string GetLastError() const override { return m_lastError; }
136
137 DB_FAILURE GetLastFailure() const override { return m_lastFailure; }
138
146
154
156 static std::string ProviderPendingMessage();
157
159 static std::string ProviderMissingMessage();
160
161private:
164 {
165 uint64_t id = 0;
166 std::set<std::string> tables;
167 };
168
171 {
172 size_t rows = 0;
173 uint64_t hash = 0;
174 std::vector<std::string> labels;
175
176 bool operator==( const PASS_DIGEST& aOther ) const
177 {
178 return rows == aOther.rows && hash == aOther.hash && labels == aOther.labels;
179 }
180 };
181
189 std::optional<PASS_DIGEST> readPass( uint64_t aSession, const std::string& aSql, const std::string& aUnorderedSql,
190 size_t aMaxRows, std::vector<std::string>& aLabels, const DB_ROW_SINK* aSink,
191 std::optional<ACE_ENGINE_OP::CLOCK::time_point> aDeadline = std::nullopt );
192
196 std::optional<uint64_t> freshSession( const std::string& aTable, ACE_ENGINE_OP::CLOCK::time_point aDeadline,
197 const std::function<bool()>& aMayStart );
198
200 bool closeSpentSessions( ACE_ENGINE_OP::CLOCK::time_point aDeadline );
201
202 bool cycleStopped() const;
203
205 bool pauseUnlessStopped( std::chrono::milliseconds aWait );
206
207 void failStopped( const std::string& aTable );
208
210 bool readVerified( const DB_TABLE_INFO& aTable, const std::vector<std::string>& aColumns,
211 std::vector<std::string>& aLabels, const DB_ROW_SINK& aSink, const DB_RESTART_SINK& aRestart );
212
214 template <typename R>
215 std::optional<R> runOnWorker( std::function<R( DB_JOB_CONTEXT& )> aJob, const DB_ROW_SINK* aSink,
216 std::shared_ptr<ACE_ENGINE_OP> aOp = nullptr,
217 std::optional<std::chrono::milliseconds> aProgressBound = std::nullopt );
218
222 void dropConnection( std::shared_ptr<ACE_ENGINE_OP> aOp = nullptr, bool aForExit = false );
223
226 bool closeOnWorker( std::vector<uint64_t> aIds, std::shared_ptr<ACE_ENGINE_OP> aOp,
227 std::optional<std::chrono::milliseconds> aBound = std::nullopt );
228
229 void fail( DB_FAILURE aFailure, std::string aError );
230
232 std::shared_ptr<ACE_ENGINE_OP> newOp() const;
233
235 void failCall( DB_FAILURE aFailure, std::string aMessage );
236
238 bool requireConnection();
239
240 std::string m_path;
241 std::string m_password;
243
245 std::shared_ptr<ACE_ENGINE_OP> m_lastOp;
246
247 std::unique_ptr<DB_WORKER_THREAD> m_worker;
248
250 uint64_t m_session = 0;
251
253 std::wstring m_progId;
254
256 static constexpr size_t MAX_CYCLE_SESSIONS = 2;
257
258 std::vector<CYCLE_SESSION> m_cycleSessions;
259
262
265
266 std::atomic<bool> m_connected{ false };
267
268 std::string m_lastError;
270};
271
272#endif // KICAD_ACE_BACKEND_H
std::string m_password
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.
std::string m_lastError
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,...
std::string m_path
std::shared_ptr< ACE_ENGINE_OP > newOp() const
ACE_BACKEND(std::string aPath, std::string aPassword, int aTimeoutSeconds)
std::unique_ptr< DB_WORKER_THREAD > m_worker
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.
static PROVIDER_STATE ProviderState()
Tells whether the ACE OLE DB provider is installed and loads.
bool IsConnected() const override
Definition ace_backend.h:97
bool ListTables(std::vector< std::string > &aTables) override
Lists the tables and views, sorted by name.
DB_STOP_CHECK m_cycleStop
Set by the outermost load cycle, which a verified read checks before every open and pass.
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.
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::vector< CYCLE_SESSION > m_cycleSessions
void BeginLoadCycle(const DB_STOP_CHECK &aStopped) override
Brackets a load cycle, in which the caller reads each table once.
bool pauseUnlessStopped(std::chrono::milliseconds aWait)
Sleeps for aWait; false if the cycle's stop check came true first.
bool Connect() override
static constexpr size_t MAX_CYCLE_SESSIONS
The most sessions a load cycle holds at once.
void failStopped(const std::string &aTable)
void EndLoadCycle() override
Closes the sessions the cycle opened, on the worker thread.
DB_FAILURE m_lastFailure
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...
void fail(DB_FAILURE aFailure, std::string aError)
std::wstring m_progId
The provider that opened the connection, which the cycle's sessions use too.
std::optional< DB_TABLE_INFO > DescribeTable(const std::string &aTable) override
int m_cycleDepth
How many load cycles are open; the sessions are closed when the last one ends.
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.
bool requireConnection()
Fails with a message and returns false unless a connection is open.
std::string GetLastError() const override
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 coul...
std::atomic< bool > m_connected
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...
void Disconnect() override
uint64_t m_session
Names this backend's connection among those the worker thread holds.
DB_FAILURE GetLastFailure() const override
~ACE_BACKEND() override
@ BUSY
The check could not start because the engine lock stayed out of reach.
@ PENDING
The check has not finished, so nothing is known yet.
static std::string ProviderMissingMessage()
The message for a source that needs the provider when ProviderState() is MISSING.
bool cycleStopped() const
static std::string ProviderPendingMessage()
The message for a source whose provider check has not finished.
std::shared_ptr< ACE_ENGINE_OP > m_lastOp
The operation the caller last ran, which a failure that drops the connection continues.
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 trus...
A read-only source of tables.
What a job running on a DB_WORKER_THREAD uses to hand rows to the caller.
std::function< bool()> DB_STOP_CHECK
True once the caller no longer wants what a read would deliver.
std::function< void(std::vector< DB_VALUE > &&)> DB_ROW_SINK
Receives one row at a time, in the order of the labels the read produced.
DB_FAILURE
Why a connection attempt failed, as far as the backend's report tells.
std::function< void()> DB_RESTART_SINK
Told that the rows delivered so far are void, because the read starts the table again from its first ...
A session opened for one load cycle, and the tables it has read, which it never reads again.
std::set< std::string > tables
What one complete pass over a table returned, as a verified read compares it.
bool operator==(const PASS_DIGEST &aOther) const
std::vector< std::string > labels
std::chrono::steady_clock CLOCK
Definition ace_backend.h:45
std::atomic< STATE > state
Definition ace_backend.h:68
@ WAITING
A job is blocked on the engine lock.
Definition ace_backend.h:50
@ ACQUIRED
The job took the lock.
Definition ace_backend.h:51
@ EXPIRED
The deadline passed first; never cleared.
Definition ace_backend.h:52
ACE_ENGINE_OP(CLOCK::time_point aDeadline)
Definition ace_backend.h:55
bool Busy() const
True if the operation is waiting for the engine lock or gave up on it.
Definition ace_backend.h:61
const CLOCK::time_point deadline
Definition ace_backend.h:67