Commit e4d34aab authored by Pavel Vainerman's avatar Pavel Vainerman

(SQLite): заготовка для интерфейса..

parent ea7a1ff4
......@@ -38,6 +38,7 @@ PKG_CHECK_MODULES(XML, libxml-2.0)
PKG_CHECK_MODULES(OMNI, omniORB4)
PKG_CHECK_MODULES(SIGC, sigc++-2.0)
PKG_CHECK_MODULES(COMCPP, libccgnu2)
PKG_CHECK_MODULES(SQLITE3, sqlite3)
# export
LDFLAGS="${OMNI_LIBS} ${XML_LIBS}"
......@@ -177,6 +178,8 @@ AC_CONFIG_FILES([Makefile
extensions/include/Makefile
extensions/DBServer-MySQL/Makefile
extensions/DBServer-MySQL/libUniSetMySQL.pc
extensions/DBServer-SQLite/Makefile
extensions/DBServer-SQLite/libUniSetSQLite.pc
extensions/IOControl/Makefile
extensions/IOControl/libUniSetIOControl.pc
extensions/ModbusMaster/Makefile
......
/* This file is part of the UniSet project
* Copyright (c) 2002 Free Software Foundation, Inc.
* Copyright (c) 2002 Pavel Vainerman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// --------------------------------------------------------------------------
/*! \file
* \author Pavel Vainerman
*/
// --------------------------------------------------------------------------
#ifndef DBServer_SQLite_H_
#define DBServer_SQLite_H_
// --------------------------------------------------------------------------
#include <map>
#include <queue>
#include "UniSetTypes.h"
#include "SQLiteInterface.h"
#include "DBServer.h"
//------------------------------------------------------------------------------------------
/*!
\page page_DBServer_SQLite (DBServer_SQLite) Реализация сервиса ведения БД на основе SQLite
- \ref sec_DBS_Comm
- \ref sec_DBS_Conf
- \ref sec_DBS_Tables
- \ref sec_DBS_Buffer
\section sec_DBS_Comm Общее описание работы DBServer_SQLite
Сервис предназначен для работы с БД SQLite. В его задачи входит
сохранение всех событий происходищих в системе в БД. К этим
событиям относятся изменение состояния датчиков, различные логи
работы процессов и т.п.
К моменту запуска, подразумевается, что неободимые таблицы уже
созданы, все необходимые настройки mysql сделаны.
\par
При работе с БД, сервис в основном пишет в БД. Обработка накопленных данных
ведётся уже другими программами (web-интерфейс).
\par
Для повышения надежности DBServer переодически ( DBServer_SQLite::PingTimer ) проверяет наличие связи с сервером БД.
В случае если связь пропала (или не была установлена при старте) DBServer пытается вновь каждые DBServer::ReconnectTimer
произвести соединение. При этом все запросы которые поступают для запии в БД, но не мгут быть записаны складываются
в буфер (см. \ref sec_DBS_Buffer).
\warning При каждой попытке восстановить соединение DBServer заново читает конф. файл. Поэтому он может подхватить
новые настройки.
\todo Может не сохранять текст, если задан код... (для экономии в БД)
\section sec_DBS_Conf Настройка DBServer
Объект DBServer берёт настройки из конфигурационного файла из секции \b<LocalDBServer>.
Возможно задать следующие параметры:
- \b dbname - название БД
- \b dbnode - узел БД
- \b dbuser - пользователь
- \b dbpass - пароль для доступа к БД
- \b pingTime - период проверки связи с сервером SQLite
- \b reconnectTime - время повторной попытки соединения с БД
\section sec_DBS_Buffer Защита от потери данных
Для того, чтобы на момент отсутствия связи с БД данные по возможности не потерялись,
сделан "кольцевой" буфер. Размер которго можно регулировать параметром "--dbserver-buffer-size"
или параметром \b bufferSize=".." в конфигурационном файле секции "<LocalDBSErver...>".
Механизм построен на том, что если связь с mysql сервером отсутствует или пропала,
то сообщения помещаются в колевой буфер, который "опустошается" как только она восстановится.
Если связь не восстановилась, а буфер достиг максимального заданного размера, то удаляются
более ранние сообщения. Эту логику можно сменить, если указать параметр "--dbserver-buffer-last-remove"
или \b bufferLastRemove="1", то терятся будут сообщения добавляемые в конец.
\section sec_DBS_Tables Таблицы SQLite
К основным таблицам относятся следующие:
\code
DROP TABLE IF EXISTS `main_history`;
CREATE TABLE `main_history` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` date NOT NULL,
`time` time NOT NULL,
`time_usec` int(10) unsigned NOT NULL,
`sensor_id` int(10) unsigned NOT NULL,
`value` double NOT NULL,
`node` int(10) unsigned NOT NULL,
`confirm` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `main_history_sensor_id` (`sensor_id`),
CONSTRAINT `sensor_id_refs_id_3d679168` FOREIGN KEY (`sensor_id`) REFERENCES `main_sensor` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `main_emergencylog`;
CREATE TABLE `main_emergencylog` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` date NOT NULL,
`time` time NOT NULL,
`time_usec` int(10) unsigned NOT NULL,
`type_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `main_emergencylog_type_id` (`type_id`),
CONSTRAINT `type_id_refs_id_a3133ca` FOREIGN KEY (`type_id`) REFERENCES `main_emergencytype` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `main_emergencyrecords`;
CREATE TABLE `main_emergencyrecords` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` date NOT NULL,
`time` time NOT NULL,
`time_usec` int(10) unsigned NOT NULL,
`log_id` int(11) NOT NULL,
`sensor_id` int(10) unsigned NOT NULL,
`value` double NOT NULL,
PRIMARY KEY (`id`),
KEY `main_emergencyrecords_log_id` (`log_id`),
KEY `main_emergencyrecords_sensor_id` (`sensor_id`),
CONSTRAINT `log_id_refs_id_77a37ea9` FOREIGN KEY (`log_id`) REFERENCES `main_emergencylog` (`id`),
CONSTRAINT `sensor_id_refs_id_436bab5e` FOREIGN KEY (`sensor_id`) REFERENCES `main_sensor` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
\endcode
*/
class DBServer_SQLite:
public DBServer
{
public:
DBServer_SQLite( UniSetTypes::ObjectId id );
DBServer_SQLite();
~DBServer_SQLite();
static const Debug::type DBLogInfoLevel = Debug::LEVEL9;
protected:
typedef std::map<int, std::string> DBTableMap;
virtual void initDB( SQLiteInterface *db ){};
virtual void initDBTableMap(DBTableMap& tblMap){};
virtual void processingMessage( UniSetTypes::VoidMessage *msg );
virtual void timerInfo( UniSetTypes::TimerMessage* tm );
virtual void sysCommand( UniSetTypes::SystemMessage* sm );
// Функции обработки пришедших сообщений
virtual void parse( UniSetTypes::SensorMessage* sm );
virtual void parse( UniSetTypes::DBMessage* dbmsg );
virtual void parse( UniSetTypes::ConfirmMessage* cmsg );
bool writeToBase( const string& query );
virtual void init_dbserver();
void createTables( SQLiteInterface* db );
inline const char* tblName(int key)
{
return tblMap[key].c_str();
}
enum Timers
{
PingTimer, /*!< таймер на переодическую проверку соединения с сервером БД */
ReconnectTimer, /*!< таймер на повторную попытку соединения с сервером БД (или восстановления связи) */
lastNumberOfTimer
};
SQLiteInterface *db;
int PingTime;
int ReconnectTime;
bool connect_ok; /*! признак наличия соеднинения с сервером БД */
bool activate;
typedef std::queue<std::string> QueryBuffer;
QueryBuffer qbuf;
unsigned int qbufSize; // размер буфера сообщений.
bool lastRemove;
void flushBuffer();
UniSetTypes::uniset_mutex mqbuf;
private:
DBTableMap tblMap;
};
//------------------------------------------------------------------------------------------
#endif
#if DISABLE_SQLITE
#else
USQLITE_VER=@LIBVER@
lib_LTLIBRARIES = libUniSet-sqlite.la
libUniSet_sqlite_la_LDFLAGS = -version-info $(USQLITE_VER)
libUniSet_sqlite_la_SOURCES = SQLiteInterface.cc DBServer_SQLite.cc
libUniSet_sqlite_la_LIBADD = $(top_builddir)/lib/libUniSet.la $(SQLITE3_LIBS)
libUniSet_sqlite_la_CXXFLAGS = $(SQLITE3_CFLAGS)
bin_PROGRAMS = uniset-sqlite-dbserver
uniset_sqlite_dbserver_LDADD = libUniSet-sqlite.la $(top_builddir)/lib/libUniSet.la
uniset_sqlite_dbserver_SOURCES = main.cc
include $(top_builddir)/conf/setting.mk
# install
#devel_include_HEADERS = *.h
#devel_includedir = $(includedir)/@PACKAGE@/sqlite
#pkgconfigdir = $(libdir)/pkgconfig
#pkgconfig_DATA = libUniSetSQLite.pc
#endif
\ No newline at end of file
/* This file is part of the UniSet project
* Copyright (c) 2002 Free Software Foundation, Inc.
* Copyright (c) 2002 Pavel Vainerman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// --------------------------------------------------------------------------
/*! \file
* \author Pavel Vainerman
*/
// --------------------------------------------------------------------------
#include <sstream>
#include "UniSetTypes.h"
#include "SQLiteInterface.h"
// --------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
// --------------------------------------------------------------------------
SQLiteInterface::SQLiteInterface():
db(0),
lastQ(""),
queryok(false),
connected(false),
opTimeout(300),
opCheckPause(50)
{
}
SQLiteInterface::~SQLiteInterface()
{
close();
delete db;
}
// -----------------------------------------------------------------------------------------
bool SQLiteInterface::connect( const string dbfile )
{
int rc = sqlite3_open(dbfile.c_str(), &db);
if( !rc )
{
cerr << sqlite3_errmsg(db) << endl;
sqlite3_close(db);
db = 0;
connected = false;
return false;
}
if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED || rc==SQLITE_INTERRUPT || rc==SQLITE_IOERR )
{
cerr << sqlite3_errmsg(db) << endl;
sqlite3_close(db);
db = 0;
connected = false;
return false;
}
connected = true;
return true;
}
// -----------------------------------------------------------------------------------------
bool SQLiteInterface::close()
{
if(db)
sqlite3_close(db);
return true;
}
// -----------------------------------------------------------------------------------------
bool SQLiteInterface::insert( const string q )
{
if( !db )
return false;
// char* errmsg;
sqlite3_stmt* pStmt;
// Компилируем SQL запрос
sqlite3_prepare(db, q.c_str(), -1, &pStmt, NULL);
int rc = sqlite3_step(pStmt);
if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED || rc==SQLITE_INTERRUPT || rc==SQLITE_IOERR )
{
if( !wait(pStmt, SQLITE_DONE) )
{
sqlite3_finalize(pStmt);
queryok=false;
return false;
}
}
sqlite3_finalize(pStmt);
queryok=true;
return true;
}
// -----------------------------------------------------------------------------------------
bool SQLiteInterface::query( const string q )
{
if( !db )
return false;
// char* errmsg = 0;
sqlite3_stmt* pStmt;
// Компилируем SQL запрос
sqlite3_prepare(db, q.c_str(), -1, &pStmt, NULL);
int rc = sqlite3_step(pStmt);
if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED || rc==SQLITE_INTERRUPT || rc==SQLITE_IOERR )
{
if( !wait(pStmt, SQLITE_ROW) )
{
sqlite3_finalize(pStmt);
queryok=false;
return false;
}
}
lastQ = q;
// int cnum = sqlite3_column_count(pStmt);
/*
while( (rc = sqlite3_step(pStmt)) == SQLITE_ROW )
{
int coln = sqlite3_data_count(pStmt);
for( int j=0; j<coln; j++ )
{
}
}
*/
sqlite3_finalize(pStmt);
queryok=true;
return true;
}
// -----------------------------------------------------------------------------------------
bool SQLiteInterface::wait( sqlite3_stmt* stmt, int result )
{
PassiveTimer ptTimeout(opTimeout);
while( !ptTimeout.checkTime() )
{
sqlite3_reset(stmt);
int rc = sqlite3_step(stmt);
if( rc == result || rc == SQLITE_DONE )
return true;
msleep(opCheckPause);
}
return false;
}
// -----------------------------------------------------------------------------------------
const string SQLiteInterface::error()
{
if( !db )
return "";
return sqlite3_errmsg(db);
}
// -----------------------------------------------------------------------------------------
const string SQLiteInterface::lastQuery()
{
return lastQ;
}
// -----------------------------------------------------------------------------------------
int SQLiteInterface::insert_id()
{
if( !db )
return 0;
return sqlite3_last_insert_rowid(db);
}
// -----------------------------------------------------------------------------------------
bool SQLiteInterface::isConnection()
{
return connected;
}
// -----------------------------------------------------------------------------------------
/* This file is part of the UniSet project
* Copyright (c) 2002 Free Software Foundation, Inc.
* Copyright (c) 2002 Pavel Vainerman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// --------------------------------------------------------------------------
/*! \file
* \author Pavel Vainerman
*/
//----------------------------------------------------------------------------
#ifndef SQLiteInterface_H_
#define SQLiteInterface_H_
// ---------------------------------------------------------------------------
#include <string>
#include <iostream>
#include <sqlite3.h>
#include "PassiveTimer.h"
// ----------------------------------------------------------------------------
class SQLiteInterface
{
public:
SQLiteInterface();
~SQLiteInterface();
bool connect( const std::string dbfile );
bool close();
inline void setOperationTimeout( timeout_t msec ){ opTimeout = msec; }
inline timeout_t getOperationTimeout(){ return opTimeout; }
inline void setOperationCheckPause( timeout_t msec ){ opCheckPause = msec; }
inline timeout_t getOperationCheckPause(){ return opCheckPause; }
bool query( const std::string q );
const std::string lastQuery();
bool insert( const std::string q );
bool isConnection();
int insert_id();
const std::string error();
protected:
bool wait( sqlite3_stmt* stmt, int result );
private:
sqlite3* db;
std::string lastQ;
bool queryok; // успешность текущего запроса
bool connected;
timeout_t opTimeout;
timeout_t opCheckPause;
};
// ----------------------------------------------------------------------------------
#endif
// ----------------------------------------------------------------------------------
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libUniSetSQLite
Description: Support library for libUniSetSQLite
Requires: libUniSet sqlite3
Version: 1.0.0
Libs: -L${libdir} -lUniSet-sqlite
Cflags: -I${includedir}/uniset -I${includedir}/sqlite
#include "Configuration.h"
#include "DBServer_SQLite.h"
#include "ObjectsActivator.h"
#include "Debug.h"
// --------------------------------------------------------------------------
using namespace UniSetTypes;
using namespace std;
// --------------------------------------------------------------------------
static void short_usage()
{
cout << "Usage: uniset-mysql-dbserver [--name ObjectId] [--confile configure.xml]\n";
}
// --------------------------------------------------------------------------
int main(int argc, char** argv)
{
try
{
if( argc > 1 && !strcmp(argv[1],"--help") )
{
short_usage();
return 0;
}
uniset_init(argc,argv,"configure.xml");
ObjectId ID = conf->getDBServer();
// определяем ID объекта
string name = conf->getArgParam("--name");
if( !name.empty())
{
if( ID != UniSetTypes::DefaultObjectId )
{
unideb[Debug::WARN] << "(DBServer::main): переопределяем ID заданнй в "
<< conf->getConfFileName() << endl;
}
ID = conf->oind->getIdByName(conf->getServicesSection()+"/"+name);
if( ID == UniSetTypes::DefaultObjectId )
{
cerr << "(DBServer::main): идентификатор '" << name
<< "' не найден в конф. файле!"
<< " в секции " << conf->getServicesSection() << endl;
return 1;
}
}
else if( ID == UniSetTypes::DefaultObjectId )
{
cerr << "(DBServer::main): Не удалось определить ИДЕНТИФИКАТОР сервера" << endl;
short_usage();
return 1;
}
DBServer_SQLite dbs(ID);
ObjectsActivator act;
act.addObject(static_cast<class UniSetObject*>(&dbs));
act.run(false);
}
catch(Exception& ex)
{
cerr << "(DBServer::main): " << ex << endl;
}
catch(...)
{
cerr << "(DBServer::main): catch ..." << endl;
}
return 0;
}
......@@ -4,8 +4,8 @@
if HAVE_EXTENTIONS
SUBDIRS = lib include SharedMemory IOControl LogicProcessor \
ModbusMaster ModbusSlave SMViewer UniNetwork UNetUDP DBServer-MySQL SharedMemoryPlus \
tests
ModbusMaster ModbusSlave SMViewer UniNetwork UNetUDP DBServer-MySQL DBServer-SQLite \
SharedMemoryPlus tests
#SMDBServer
#SharedMemoryPlus
#UDPExchange
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment