SNode.C
Loading...
Searching...
No Matches
MariaDBConnection.cpp
Go to the documentation of this file.
1/*
2 * SNode.C - A Slim Toolkit for Network Communication
3 * Copyright (C) Volker Christian <me@vchrist.at>
4 * 2020, 2021, 2022, 2023, 2024, 2025
5 * 2021, 2022 Daniel Flockert
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21/*
22 * MIT License
23 *
24 * Permission is hereby granted, free of charge, to any person obtaining a copy
25 * of this software and associated documentation files (the "Software"), to deal
26 * in the Software without restriction, including without limitation the rights
27 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
28 * copies of the Software, and to permit persons to whom the Software is
29 * furnished to do so, subject to the following conditions:
30 *
31 * The above copyright notice and this permission notice shall be included in
32 * all copies or substantial portions of the Software.
33 *
34 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
39 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
40 * THE SOFTWARE.
41 */
42
43#include "database/mariadb/MariaDBConnection.h"
44
45#include "database/mariadb/MariaDBClient.h"
46#include "database/mariadb/commands/async/MariaDBConnectCommand.h"
47
48#ifndef DOXYGEN_SHOULD_SKIP_THIS
49
50#include "core/SNodeC.h"
51#include "log/Logger.h"
52#include "utils/Timeval.h"
53
54#include <mysql.h>
55#include <string>
56#include <utility>
57
58#endif /* DOXYGEN_SHOULD_SKIP_THIS */
59
60namespace database::mariadb {
61
63 const MariaDBConnectionDetails& connectionDetails,
64 const std::function<void(const MariaDBState&)>& onStateChanged)
68 , mariaDBClient(mariaDBClient)
69 , mysql(mysql_init(nullptr))
70 , connectionName(connectionDetails.connectionName)
71 , commandStartEvent("MariaDBCommandStartEvent", this)
73 mysql_options(mysql, MYSQL_OPT_NONBLOCK, nullptr);
74
75 execute_async(std::move(MariaDBCommandSequence().execute_async(new database::mariadb::commands::async::MariaDBConnectCommand(
76 connectionDetails,
77 [this]() {
78 if (mysql_errno(mysql) == 0) {
79 const int fd = mysql_get_socket(mysql);
80
81 if (ReadEventReceiver::enable(fd) && WriteEventReceiver::enable(fd) && ExceptionalConditionEventReceiver::enable(fd)) {
82 ReadEventReceiver::suspend();
83 WriteEventReceiver::suspend();
84 ExceptionalConditionEventReceiver::suspend();
85
86 connected = true;
87 } else {
88 if (ReadEventReceiver::isEnabled()) {
89 ReadEventReceiver::disable();
90 }
91 if (WriteEventReceiver::isEnabled()) {
92 WriteEventReceiver::disable();
93 }
94 if (ExceptionalConditionEventReceiver::isEnabled()) {
95 ExceptionalConditionEventReceiver::disable();
96 }
97
98 LOG(ERROR) << this->connectionName << " MariaDB: Descriptor not registered in SNode.C eventloop";
99 }
100 }
101 },
102 [this]() {
103 LOG(DEBUG) << this->connectionName << " MariaDB connect: success";
104
105 this->onStateChanged({.connected = true});
106 },
107 [this](const std::string& errorString, unsigned int errorNumber) {
108 LOG(WARNING) << this->connectionName << " MariaDB connect: error: " << errorString << " : " << errorNumber;
109
110 this->onStateChanged({.error = errorNumber, .errorMessage = errorString});
111 }))));
112 }
113
115 for (MariaDBCommandSequence& mariaDBCommandSequence : commandSequenceQueue) {
116 for (MariaDBCommand* mariaDBCommand : mariaDBCommandSequence.sequence()) {
117 if (core::SNodeC::state() == core::State::RUNNING && connected) {
118 mariaDBCommand->commandError(mysql_error(mysql), mysql_errno(mysql));
119 }
120
121 delete mariaDBCommand;
122 }
123 }
124
125 if (mariaDBClient != nullptr) {
127 }
128
129 mysql_close(mysql);
130 mysql_library_end();
131 }
132
134 if (currentCommand == nullptr && commandSequenceQueue.empty()) {
136 }
137
138 commandSequenceQueue.emplace_back(std::move(commandSequence));
139
140 return commandSequenceQueue.back();
141 }
142
144 mariaDBCommand->commandStart(mysql, utils::Timeval::currentTime());
145
146 if (mysql_errno(mysql) == 0) {
147 if (mariaDBCommand->commandCompleted()) {
148 }
149 } else {
150 mariaDBCommand->commandError(mysql_error(mysql), mysql_errno(mysql));
151 }
152
153 delete mariaDBCommand;
154 }
155
156 void MariaDBConnection::commandStart(const utils::Timeval& currentTime) {
157 if (!commandSequenceQueue.empty()) {
158 currentCommand = commandSequenceQueue.front().nextCommand();
159
160 LOG(DEBUG) << connectionName << " MariaDB start: " << currentCommand->commandInfo();
161
164 } else if (mariaDBClient != nullptr) {
167 }
168 } else {
172 }
173 }
174
176 if (currentCommand != nullptr) {
178 } else if ((status & MYSQL_WAIT_READ) != 0 && commandSequenceQueue.empty()) {
182 }
183 }
184
186 LOG(DEBUG) << connectionName << " MariaDB completed: " << currentCommand->commandInfo();
187 commandSequenceQueue.front().commandCompleted();
188
189 if (commandSequenceQueue.front().empty()) {
190 commandSequenceQueue.pop_front();
191 }
192
193 delete currentCommand;
194 currentCommand = nullptr;
195 }
196
198 mariaDBClient = nullptr;
199
200 if (currentCommand == nullptr && commandSequenceQueue.empty()) {
203 }
206 }
209 }
210 }
211 }
212
213 void MariaDBConnection::checkStatus(int status) {
214 if (connected) {
215 if ((status & MYSQL_WAIT_READ) != 0) {
218 }
219 } else if (!ReadEventReceiver::isSuspended()) {
221 }
222
223 if ((status & MYSQL_WAIT_WRITE) != 0) {
226 }
227 } else if (!WriteEventReceiver::isSuspended()) {
229 }
230
231 if ((status & MYSQL_WAIT_EXCEPT) != 0) {
234 }
237 }
238
239 if ((status & MYSQL_WAIT_TIMEOUT) != 0) {
240 ReadEventReceiver::setTimeout(mysql_get_timeout_value(mysql));
241 // WriteEventReceiver::setTimeout(mysql_get_timeout_value(mysql));
242 // ExceptionalConditionEventReceiver::setTimeout(mysql_get_timeout_value(mysql));
243 } else {
245 // WriteEventReceiver::setTimeout(core::DescriptorEventReceiver::TIMEOUT::DEFAULT);
246 // ExceptionalConditionEventReceiver::setTimeout(core::DescriptorEventReceiver::TIMEOUT::DEFAULT);
247 }
248
249 if (status == 0) {
250 if (mysql_errno(mysql) == 0) {
253 }
254 } else {
255 currentCommand->commandError(mysql_error(mysql), mysql_errno(mysql));
257 }
259 }
260 } else {
261 currentCommand->commandError(mysql_error(mysql), mysql_errno(mysql));
263
264 delete this;
265 }
266 }
267
269 commandContinue(MYSQL_WAIT_READ);
270 }
271
273 commandContinue(MYSQL_WAIT_WRITE);
274 }
275
277 commandContinue(MYSQL_WAIT_EXCEPT);
278 }
279
281 commandContinue(MYSQL_WAIT_TIMEOUT);
282 }
283
285 commandContinue(MYSQL_WAIT_TIMEOUT);
286 }
287
289 commandContinue(MYSQL_WAIT_TIMEOUT);
290 }
291
293 LOG(ERROR) << connectionName << " MariaDB: Lost connection";
294
295 if (mariaDBClient != nullptr) {
296 onStateChanged({});
297 }
298
299 delete this;
300 }
301
302 MariaDBCommandStartEvent::MariaDBCommandStartEvent(const std::string& name, MariaDBConnection* mariaDBConnection)
303 : core::EventReceiver(name)
304 , mariaDBConnection(mariaDBConnection) {
305 }
306
307 void MariaDBCommandStartEvent::onEvent(const utils::Timeval& currentTime) {
309 }
310
314
315} // namespace database::mariadb
void setTimeout(const utils::Timeval &timeout)
EventReceiver(const std::string &name)
MariaDBCommandSequence & execute_async(MariaDBCommand *mariaDBCommand) final
void onEvent(const utils::Timeval &currentTime) override
virtual int commandContinue(int status)=0
void setMariaDBConnection(MariaDBConnection *mariaDBConnection)
virtual void commandError(const std::string &errorString, unsigned int errorNumber)=0
MariaDBCommandStartEvent commandStartEvent
MariaDBConnection(MariaDBClient *mariaDBClient, const MariaDBConnectionDetails &connectionDetails, const std::function< void(const MariaDBState &)> &onStateChanged)
MariaDBCommandSequence & execute_async(MariaDBCommandSequence &&commandSequence)
void commandStart(const utils::Timeval &currentTime)
void execute_sync(MariaDBCommand *mariaDBCommand)
static Timeval currentTime()
Definition Timeval.cpp:76
Definition Config.h:59