Added DBDriverSqlite3 tests

This commit is contained in:
matlabbe
2026-05-17 09:53:57 -07:00
parent 59ba6e54bd
commit c102c687d9
5 changed files with 526 additions and 227 deletions
+9 -7
View File
@@ -185,15 +185,17 @@ if(BUILD_TESTING)
set(TEST_DATA_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/data") set(TEST_DATA_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/data")
endif() endif()
OPTION(ENABLE_COVERAGE "Build with gcov/llvm coverage instrumentation (for CI)" OFF) OPTION(ENABLE_COVERAGE "Build with gcov/lcov coverage (GCC/Clang, Debug only; see coverage-report.sh)" OFF)
IF(ENABLE_COVERAGE) IF(ENABLE_COVERAGE)
IF(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") IF(NOT CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
MESSAGE(STATUS "Coverage instrumentation enabled") MESSAGE(FATAL_ERROR "ENABLE_COVERAGE requires GCC or Clang with gcov/lcov (current: ${CMAKE_CXX_COMPILER_ID}).")
ADD_COMPILE_OPTIONS(--coverage -O0 -g)
ADD_LINK_OPTIONS(--coverage)
ELSE()
MESSAGE(WARNING "ENABLE_COVERAGE is only supported with GCC or Clang")
ENDIF() ENDIF()
IF(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
MESSAGE(FATAL_ERROR "ENABLE_COVERAGE requires CMAKE_BUILD_TYPE=Debug (current: \"${CMAKE_BUILD_TYPE}\").")
ENDIF()
MESSAGE(STATUS "Coverage instrumentation enabled")
ADD_COMPILE_OPTIONS(--coverage -O0 -g)
ADD_LINK_OPTIONS(--coverage)
ENDIF() ENDIF()
####### DEPENDENCIES ####### ####### DEPENDENCIES #######
+317 -216
View File
@@ -1,216 +1,317 @@
/* /*
Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright * Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer. notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright * Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution. documentation and/or other materials provided with the distribution.
* Neither the name of the Universite de Sherbrooke nor the * Neither the name of the Universite de Sherbrooke nor the
names of its contributors may be used to endorse or promote products names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission. derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef DBDRIVERSQLITE3_H_ #ifndef DBDRIVERSQLITE3_H_
#define DBDRIVERSQLITE3_H_ #define DBDRIVERSQLITE3_H_
#include "rtabmap/core/rtabmap_core_export.h" // DLL export/import defines #include "rtabmap/core/rtabmap_core_export.h" // DLL export/import defines
#include "rtabmap/core/DBDriver.h" #include "rtabmap/core/DBDriver.h"
#include <opencv2/features2d/features2d.hpp> #include <opencv2/features2d/features2d.hpp>
typedef struct sqlite3_stmt sqlite3_stmt; typedef struct sqlite3_stmt sqlite3_stmt;
typedef struct sqlite3 sqlite3; typedef struct sqlite3 sqlite3;
namespace rtabmap { namespace rtabmap {
class RTABMAP_CORE_EXPORT DBDriverSqlite3: public DBDriver { /**
public: * @class DBDriverSqlite3
DBDriverSqlite3(const ParametersMap & parameters = ParametersMap()); * @brief SQLite3 implementation of @ref DBDriver for RTAB-Map map databases.
virtual ~DBDriverSqlite3(); *
* This is the default driver returned by @ref DBDriver::create(). It stores signatures,
virtual void parseParameters(const ParametersMap & parameters); * links, visual words, statistics and sensor payloads in a single \c .db file using
virtual bool isInMemory() const {return getUrl().empty() || _dbInMemory;} * the SQLite C API.
void setDbInMemory(bool dbInMemory); *
void setJournalMode(int journalMode); * **Storage modes**
void setCacheSize(unsigned int cacheSize); * - **File-backed** (default): the database is read/written directly on disk at @ref getUrl().
void setSynchronous(int synchronous); * - **In-memory**: when @ref isInMemory() is true, SQLite uses \c :memory: and the file at
void setTempStore(int tempStore); * @ref getUrl() (if any) is loaded at open and optionally saved on @ref closeConnection().
*
protected: * **SQLite PRAGMA tuning** (applied on connect and when setters are called while connected):
virtual bool connectDatabaseQuery(const std::string & url, bool overwritten = false, bool readOnly = false); * - @ref setCacheSize() — page cache size in pages
virtual void disconnectDatabaseQuery(bool save = true, const std::string & outputUrl = ""); * - @ref setJournalMode() — rollback journal mode (DELETE … OFF)
virtual bool isConnectedQuery() const; * - @ref setSynchronous() — fsync policy (OFF / NORMAL / FULL)
virtual unsigned long getMemoryUsedQuery() const; // In bytes * - @ref setTempStore() — storage for temporary tables and indices
virtual bool getDatabaseVersionQuery(std::string & version) const; *
virtual long getNodesMemoryUsedQuery() const; * Configure via @ref Parameters::kDbSqlite3InMemory(), @ref Parameters::kDbSqlite3CacheSize(),
virtual long getLinksMemoryUsedQuery() const; * @ref Parameters::kDbSqlite3JournalMode(), @ref Parameters::kDbSqlite3Synchronous() and
virtual long getImagesMemoryUsedQuery() const; * @ref Parameters::kDbSqlite3TempStore(), or call the setters directly.
virtual long getDepthImagesMemoryUsedQuery() const; *
virtual long getCalibrationsMemoryUsedQuery() const; * @see DBDriver
virtual long getGridsMemoryUsedQuery() const; * @see DBDriver::create()
virtual long getLaserScansMemoryUsedQuery() const; */
virtual long getUserDataMemoryUsedQuery() const; class RTABMAP_CORE_EXPORT DBDriverSqlite3: public DBDriver {
virtual long getWordsMemoryUsedQuery() const; public:
virtual long getFeaturesMemoryUsedQuery() const; /**
virtual long getStatisticsMemoryUsedQuery() const; * @brief Construct driver with optional SQLite-specific parameters.
virtual int getLastNodesSizeQuery() const; * @param parameters Map of parameters (see class description).
virtual int getLastDictionarySizeQuery() const; */
virtual int getTotalNodesSizeQuery() const; DBDriverSqlite3(const ParametersMap & parameters = ParametersMap());
virtual int getTotalDictionarySizeQuery() const; virtual ~DBDriverSqlite3();
virtual ParametersMap getLastParametersQuery() const;
virtual std::map<std::string, float> getStatisticsQuery(int nodeId, double & stamp, std::vector<int> * wmState) const; /** @brief Apply SQLite parameters from the map; forwards to @ref DBDriver::parseParameters(). */
virtual std::map<int, std::pair<std::map<std::string, float>, double> > getAllStatisticsQuery() const; virtual void parseParameters(const ParametersMap & parameters);
virtual std::map<int, std::vector<int> > getAllStatisticsWmStatesQuery() const; /**
* @brief True when the database runs in RAM instead of on disk.
virtual void executeNoResultQuery(const std::string & sql) const; * @return True if @ref getUrl() is empty or @ref setDbInMemory(true) was used.
*/
virtual void getWeightQuery(int signatureId, int & weight) const; virtual bool isInMemory() const {return getUrl().empty() || _dbInMemory;}
/**
virtual void saveQuery(const std::list<Signature *> & signatures); * @brief Enable or disable in-memory mode.
virtual void saveQuery(const std::list<VisualWord *> & words) const; * If connected, the connection is closed and reopened with the new mode.
virtual void updateQuery(const std::list<Signature *> & signatures, bool updateTimestamp) const; */
virtual void updateQuery(const std::list<VisualWord *> & words, bool updateTimestamp) const; void setDbInMemory(bool dbInMemory);
/**
virtual void addLinkQuery(const Link & link) const; * @brief Set SQLite rollback journal mode (`PRAGMA journal_mode`).
virtual void updateLinkQuery(const Link & link) const; *
* Controls how SQLite stores the transaction journal used for atomic commit and rollback.
virtual void updateOccupancyGridQuery( * See https://www.sqlite.org/pragma.html#pragma_journal_mode
int nodeId, *
const cv::Mat & ground, * @param journalMode Accepted values (invalid values are ignored). RTAB-Map default:
const cv::Mat & obstacles, * @ref Parameters::defaultDbSqlite3JournalMode() = **3 (MEMORY)** (@ref Parameters::kDbSqlite3JournalMode()).
const cv::Mat & empty, * - **0 — DELETE** (SQLite default): the journal file is deleted at the end of each transaction.
float cellSize, * Good general-purpose balance of safety and speed.
const cv::Point3f & viewpoint) const; * - **1 — TRUNCATE**: the journal is truncated to zero length instead of being unlinked; can be
* faster on some filesystems than DELETE.
virtual void updateCalibrationQuery( * - **2 — PERSIST**: the journal file is not deleted; only its header is zeroed after commit,
int nodeId, * reducing create/delete overhead at the cost of always keeping a journal file on disk.
const std::vector<CameraModel> & models, * - **3 — MEMORY** (RTAB-Map default): the journal is held in RAM only (not written to disk). Faster, but the
const std::vector<StereoCameraModel> & stereoModels) const; * database cannot be rolled back after a crash and may corrupt if the process dies mid-write.
* - **4 — OFF**: no rollback journal. Fastest, but a crash or power loss during a write can
virtual void updateDepthImageQuery( * leave the database inconsistent; transactions cannot be rolled back atomically.
int nodeId, */
const cv::Mat & image, void setJournalMode(int journalMode);
const std::string & format) const;
/**
void updateLaserScanQuery( * @brief Set the number of database pages kept in SQLite's page cache (`PRAGMA cache_size`).
int nodeId, *
const LaserScan & scan) const; * A larger cache reduces disk I/O when the working set fits in memory. The effective memory
* is approximately `cacheSize * page_size` bytes (page size is usually 4096 bytes unless
virtual void addStatisticsQuery(const Statistics & statistics, bool saveWmState) const; * changed with `PRAGMA page_size`). Only positive values are used (page count); see
virtual void savePreviewImageQuery(const cv::Mat & image) const; * https://www.sqlite.org/pragma.html#pragma_cache_size
virtual cv::Mat loadPreviewImageQuery() const; *
virtual void saveOptimizedPosesQuery(const std::map<int, Transform> & optimizedPoses, const Transform & lastlocalizationPose) const; * @param cacheSize Number of pages to cache. RTAB-Map default:
virtual std::map<int, Transform> loadOptimizedPosesQuery(Transform * lastlocalizationPose = 0) const; * @ref Parameters::defaultDbSqlite3CacheSize() = **10000** (@ref Parameters::kDbSqlite3CacheSize()).
virtual void save2DMapQuery(const cv::Mat & map, float xMin, float yMin, float cellSize) const; */
virtual cv::Mat load2DMapQuery(float & xMin, float & yMin, float & cellSize) const; void setCacheSize(unsigned int cacheSize);
virtual void saveOptimizedMeshQuery(
const cv::Mat & cloud, /**
const std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > & polygons, * @brief Set how aggressively SQLite syncs the database file to disk (`PRAGMA synchronous`).
#if PCL_VERSION_COMPARE(>=, 1, 8, 0) *
const std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > & texCoords, * Trade-off between durability after a crash or power loss and write performance.
#else * See https://www.sqlite.org/pragma.html#pragma_synchronous
const std::vector<std::vector<Eigen::Vector2f> > & texCoords, *
#endif * @param synchronous Accepted values (invalid values are ignored). RTAB-Map default:
const cv::Mat & textures) const; * @ref Parameters::defaultDbSqlite3Synchronous() = **0 (OFF)** (@ref Parameters::kDbSqlite3Synchronous()).
virtual cv::Mat loadOptimizedMeshQuery( * - **0 — OFF** (RTAB-Map default): SQLite does not wait for data to reach persistent storage. Fastest; a system
std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > * polygons, * crash or power loss during a transaction may corrupt the database.
#if PCL_VERSION_COMPARE(>=, 1, 8, 0) * - **1 — NORMAL**: syncs at the most critical moments (SQLite default in many builds). A crash
std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > * texCoords, * may lose the last transaction but the database file structure usually stays valid.
#else * - **2 — FULL**: syncs after every transaction commit. Slowest; strongest guarantee that a
std::vector<std::vector<Eigen::Vector2f> > * texCoords, * committed transaction survives a power loss (when the OS honors fsync).
#endif */
cv::Mat * textures) const; void setSynchronous(int synchronous);
virtual void saveFlannIndexQuery(const std::vector<unsigned char> & indexData) const; /**
* @brief Set where SQLite stores temporary tables and indices (`PRAGMA temp_store`).
// Load objects *
virtual void loadQuery(VWDictionary & dictionary, bool lastStateOnly = true) const; * Affects internal temp storage used for some queries and operations, not RTAB-Map map data.
virtual void loadLastNodesQuery(std::list<Signature *> & signatures, bool loadWordIdsOnly) const; * See https://www.sqlite.org/pragma.html#pragma_temp_store
virtual void loadSignaturesQuery(const std::list<int> & ids, std::list<Signature *> & signatures, bool loadWordIdsOnly) const; *
virtual void loadWordsQuery(const std::set<int> & wordIds, std::list<VisualWord *> & vws) const; * @param tempStore Accepted values (invalid values are ignored). RTAB-Map default:
virtual void loadLinksQuery(int signatureId, std::multimap<int, Link> & links, Link::Type type = Link::kUndef) const; * @ref Parameters::defaultDbSqlite3TempStore() = **2 (MEMORY)** (@ref Parameters::kDbSqlite3TempStore()).
* - **0 — DEFAULT**: use SQLite's compile-time default (often FILE, i.e. on-disk temp files).
virtual void loadNodeDataQuery(std::list<Signature *> & signatures, bool images=true, bool scan=true, bool userData=true, bool occupancyGrid=true) const; * - **1 — FILE**: store temporary tables and indices in temporary files in the directory
virtual bool getCalibrationQuery(int signatureId, std::vector<CameraModel> & models, std::vector<StereoCameraModel> & stereoModels) const; * given by `PRAGMA temp_store_directory` or the system temp folder.
virtual bool getLaserScanInfoQuery(int signatureId, LaserScan & info) const; * - **2 — MEMORY** (RTAB-Map default): store temporary tables and indices in RAM. Can speed up heavy queries
virtual bool getNodeInfoQuery(int signatureId, Transform & pose, int & mapId, int & weight, std::string & label, double & stamp, Transform & groundTruthPose, std::vector<float> & velocity, GPS & gps, EnvSensors & sensors) const; * but increases memory use; large temp structures may still spill to disk depending on build.
virtual void getLocalFeaturesQuery(int signatureId, std::multimap<int, int> & words, std::vector<cv::KeyPoint> & keypoints, std::vector<cv::Point3f> & points, cv::Mat & descriptors) const; */
virtual void getLastNodeIdsQuery(std::set<int> & ids) const; void setTempStore(int tempStore);
virtual void getAllNodeIdsQuery(std::set<int> & ids, bool ignoreChildren, bool ignoreBadSignatures, bool ignoreIntermediateNodes) const;
virtual void getAllOdomPosesQuery(std::map<int, Transform> & poses, bool ignoreChildren, bool ignoreIntermediateNodes) const; protected:
virtual void getAllLinksQuery(std::multimap<int, Link> & links, bool ignoreNullLinks, bool withLandmarks) const; virtual bool connectDatabaseQuery(const std::string & url, bool overwritten = false, bool readOnly = false);
virtual void getLastIdQuery(const std::string & tableName, int & id, const std::string & fieldName="id") const; virtual void disconnectDatabaseQuery(bool save = true, const std::string & outputUrl = "");
virtual void getInvertedIndexNiQuery(int signatureId, int & ni) const; virtual bool isConnectedQuery() const;
virtual void getNodesObservingLandmarkQuery(int landmarkId, std::map<int, Link> & nodes) const; virtual unsigned long getMemoryUsedQuery() const; // In bytes
virtual void getNodeIdByLabelQuery(const std::string & label, int & id) const; virtual bool getDatabaseVersionQuery(std::string & version) const;
virtual void getAllLabelsQuery(std::map<int, std::string> & labels) const; virtual long getNodesMemoryUsedQuery() const;
virtual long getLinksMemoryUsedQuery() const;
private: virtual long getImagesMemoryUsedQuery() const;
std::string queryStepNode() const; virtual long getDepthImagesMemoryUsedQuery() const;
std::string queryStepImage() const; virtual long getCalibrationsMemoryUsedQuery() const;
std::string queryStepDepth() const; virtual long getGridsMemoryUsedQuery() const;
std::string queryStepCalibrationUpdate() const; virtual long getLaserScansMemoryUsedQuery() const;
std::string queryStepDepthUpdate() const; virtual long getUserDataMemoryUsedQuery() const;
std::string queryStepScanUpdate() const; virtual long getWordsMemoryUsedQuery() const;
std::string queryStepSensorData() const; virtual long getFeaturesMemoryUsedQuery() const;
std::string queryStepLinkUpdate() const; virtual long getStatisticsMemoryUsedQuery() const;
std::string queryStepLink() const; virtual int getLastNodesSizeQuery() const;
std::string queryStepWordsChanged() const; virtual int getLastDictionarySizeQuery() const;
std::string queryStepKeypoint() const; virtual int getTotalNodesSizeQuery() const;
std::string queryStepGlobalDescriptor() const; virtual int getTotalDictionarySizeQuery() const;
std::string queryStepOccupancyGridUpdate() const; virtual ParametersMap getLastParametersQuery() const;
void stepNode(sqlite3_stmt * ppStmt, const Signature * s) const; virtual std::map<std::string, float> getStatisticsQuery(int nodeId, double & stamp, std::vector<int> * wmState) const;
void stepImage(sqlite3_stmt * ppStmt, int id, const cv::Mat & imageBytes) const; virtual std::map<int, std::pair<std::map<std::string, float>, double> > getAllStatisticsQuery() const;
void stepDepth(sqlite3_stmt * ppStmt, const SensorData & sensorData) const; virtual std::map<int, std::vector<int> > getAllStatisticsWmStatesQuery() const;
void stepCalibrationUpdate(sqlite3_stmt * ppStmt, int nodeId, const std::vector<CameraModel> & models, const std::vector<StereoCameraModel> & stereoModels) const;
void stepDepthUpdate(sqlite3_stmt * ppStmt, int nodeId, const cv::Mat & image, const std::string & format) const; virtual void executeNoResultQuery(const std::string & sql) const;
void stepScanUpdate(sqlite3_stmt * ppStmt, int nodeId, const LaserScan & image) const;
void stepSensorData(sqlite3_stmt * ppStmt, const SensorData & sensorData) const; virtual void getWeightQuery(int signatureId, int & weight) const;
void stepLink(sqlite3_stmt * ppStmt, const Link & link) const;
void stepWordsChanged(sqlite3_stmt * ppStmt, int signatureId, int oldWordId, int newWordId) const; virtual void saveQuery(const std::list<Signature *> & signatures);
void stepKeypoint(sqlite3_stmt * ppStmt, int nodeID, int wordId, const cv::KeyPoint & kp, const cv::Point3f & pt, const cv::Mat & descriptor) const; virtual void saveQuery(const std::list<VisualWord *> & words) const;
void stepGlobalDescriptor(sqlite3_stmt * ppStmt, int nodeId, const GlobalDescriptor & descriptor) const; virtual void updateQuery(const std::list<Signature *> & signatures, bool updateTimestamp) const;
void stepOccupancyGridUpdate(sqlite3_stmt * ppStmt, virtual void updateQuery(const std::list<VisualWord *> & words, bool updateTimestamp) const;
int nodeId,
const cv::Mat & ground, virtual void addLinkQuery(const Link & link) const;
const cv::Mat & obstacles, virtual void updateLinkQuery(const Link & link) const;
const cv::Mat & empty,
float cellSize, virtual void updateOccupancyGridQuery(
const cv::Point3f & viewpoint) const; int nodeId,
const cv::Mat & ground,
private: const cv::Mat & obstacles,
void loadWordsQuery(std::list<Signature *> & signatures) const; const cv::Mat & empty,
void loadWordIdsQuery(std::list<Signature *> & signatures) const; float cellSize,
void loadLinksQuery(std::list<Signature *> & signatures) const; const cv::Point3f & viewpoint) const;
int loadOrSaveDb(sqlite3 *pInMemory, const std::string & fileName, int isSave) const;
virtual void updateCalibrationQuery(
protected: int nodeId,
sqlite3 * _ppDb; const std::vector<CameraModel> & models,
std::string _version; const std::vector<StereoCameraModel> & stereoModels) const;
private: virtual void updateDepthImageQuery(
unsigned long _memoryUsedEstimate; int nodeId,
bool _dbInMemory; const cv::Mat & image,
unsigned int _cacheSize; const std::string & format) const;
int _journalMode;
int _synchronous; void updateLaserScanQuery(
int _tempStore; int nodeId,
}; const LaserScan & scan) const;
} virtual void addStatisticsQuery(const Statistics & statistics, bool saveWmState) const;
virtual void savePreviewImageQuery(const cv::Mat & image) const;
#endif /* DBDRIVERSQLITE3_H_ */ virtual cv::Mat loadPreviewImageQuery() const;
virtual void saveOptimizedPosesQuery(const std::map<int, Transform> & optimizedPoses, const Transform & lastlocalizationPose) const;
virtual std::map<int, Transform> loadOptimizedPosesQuery(Transform * lastlocalizationPose = 0) const;
virtual void save2DMapQuery(const cv::Mat & map, float xMin, float yMin, float cellSize) const;
virtual cv::Mat load2DMapQuery(float & xMin, float & yMin, float & cellSize) const;
virtual void saveOptimizedMeshQuery(
const cv::Mat & cloud,
const std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > & polygons,
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
const std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > & texCoords,
#else
const std::vector<std::vector<Eigen::Vector2f> > & texCoords,
#endif
const cv::Mat & textures) const;
virtual cv::Mat loadOptimizedMeshQuery(
std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > * polygons,
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > * texCoords,
#else
std::vector<std::vector<Eigen::Vector2f> > * texCoords,
#endif
cv::Mat * textures) const;
virtual void saveFlannIndexQuery(const std::vector<unsigned char> & indexData) const;
// Load objects
virtual void loadQuery(VWDictionary & dictionary, bool lastStateOnly = true) const;
virtual void loadLastNodesQuery(std::list<Signature *> & signatures, bool loadWordIdsOnly) const;
virtual void loadSignaturesQuery(const std::list<int> & ids, std::list<Signature *> & signatures, bool loadWordIdsOnly) const;
virtual void loadWordsQuery(const std::set<int> & wordIds, std::list<VisualWord *> & vws) const;
virtual void loadLinksQuery(int signatureId, std::multimap<int, Link> & links, Link::Type type = Link::kUndef) const;
virtual void loadNodeDataQuery(std::list<Signature *> & signatures, bool images=true, bool scan=true, bool userData=true, bool occupancyGrid=true) const;
virtual bool getCalibrationQuery(int signatureId, std::vector<CameraModel> & models, std::vector<StereoCameraModel> & stereoModels) const;
virtual bool getLaserScanInfoQuery(int signatureId, LaserScan & info) const;
virtual bool getNodeInfoQuery(int signatureId, Transform & pose, int & mapId, int & weight, std::string & label, double & stamp, Transform & groundTruthPose, std::vector<float> & velocity, GPS & gps, EnvSensors & sensors) const;
virtual void getLocalFeaturesQuery(int signatureId, std::multimap<int, int> & words, std::vector<cv::KeyPoint> & keypoints, std::vector<cv::Point3f> & points, cv::Mat & descriptors) const;
virtual void getLastNodeIdsQuery(std::set<int> & ids) const;
virtual void getAllNodeIdsQuery(std::set<int> & ids, bool ignoreChildren, bool ignoreBadSignatures, bool ignoreIntermediateNodes) const;
virtual void getAllOdomPosesQuery(std::map<int, Transform> & poses, bool ignoreChildren, bool ignoreIntermediateNodes) const;
virtual void getAllLinksQuery(std::multimap<int, Link> & links, bool ignoreNullLinks, bool withLandmarks) const;
virtual void getLastIdQuery(const std::string & tableName, int & id, const std::string & fieldName="id") const;
virtual void getInvertedIndexNiQuery(int signatureId, int & ni) const;
virtual void getNodesObservingLandmarkQuery(int landmarkId, std::map<int, Link> & nodes) const;
virtual void getNodeIdByLabelQuery(const std::string & label, int & id) const;
virtual void getAllLabelsQuery(std::map<int, std::string> & labels) const;
private:
std::string queryStepNode() const;
std::string queryStepImage() const;
std::string queryStepDepth() const;
std::string queryStepCalibrationUpdate() const;
std::string queryStepDepthUpdate() const;
std::string queryStepScanUpdate() const;
std::string queryStepSensorData() const;
std::string queryStepLinkUpdate() const;
std::string queryStepLink() const;
std::string queryStepWordsChanged() const;
std::string queryStepKeypoint() const;
std::string queryStepGlobalDescriptor() const;
std::string queryStepOccupancyGridUpdate() const;
void stepNode(sqlite3_stmt * ppStmt, const Signature * s) const;
void stepImage(sqlite3_stmt * ppStmt, int id, const cv::Mat & imageBytes) const;
void stepDepth(sqlite3_stmt * ppStmt, const SensorData & sensorData) const;
void stepCalibrationUpdate(sqlite3_stmt * ppStmt, int nodeId, const std::vector<CameraModel> & models, const std::vector<StereoCameraModel> & stereoModels) const;
void stepDepthUpdate(sqlite3_stmt * ppStmt, int nodeId, const cv::Mat & image, const std::string & format) const;
void stepScanUpdate(sqlite3_stmt * ppStmt, int nodeId, const LaserScan & image) const;
void stepSensorData(sqlite3_stmt * ppStmt, const SensorData & sensorData) const;
void stepLink(sqlite3_stmt * ppStmt, const Link & link) const;
void stepWordsChanged(sqlite3_stmt * ppStmt, int signatureId, int oldWordId, int newWordId) const;
void stepKeypoint(sqlite3_stmt * ppStmt, int nodeID, int wordId, const cv::KeyPoint & kp, const cv::Point3f & pt, const cv::Mat & descriptor) const;
void stepGlobalDescriptor(sqlite3_stmt * ppStmt, int nodeId, const GlobalDescriptor & descriptor) const;
void stepOccupancyGridUpdate(sqlite3_stmt * ppStmt,
int nodeId,
const cv::Mat & ground,
const cv::Mat & obstacles,
const cv::Mat & empty,
float cellSize,
const cv::Point3f & viewpoint) const;
private:
void loadWordsQuery(std::list<Signature *> & signatures) const;
void loadWordIdsQuery(std::list<Signature *> & signatures) const;
void loadLinksQuery(std::list<Signature *> & signatures) const;
int loadOrSaveDb(sqlite3 *pInMemory, const std::string & fileName, int isSave) const;
protected:
sqlite3 * _ppDb; ///< Open SQLite connection (null when disconnected)
std::string _version; ///< Schema version read from the database
private:
unsigned long _memoryUsedEstimate;
bool _dbInMemory;
unsigned int _cacheSize;
int _journalMode;
int _synchronous;
int _tempStore;
};
}
#endif /* DBDRIVERSQLITE3_H_ */
+20 -4
View File
@@ -272,10 +272,26 @@ class RTABMAP_CORE_EXPORT Parameters
//Database //Database
RTABMAP_PARAM(DbSqlite3, InMemory, bool, false, "Using database in the memory instead of a file on the hard disk."); RTABMAP_PARAM(DbSqlite3, InMemory, bool, false, "Using database in the memory instead of a file on the hard disk.");
RTABMAP_PARAM(DbSqlite3, CacheSize, unsigned int, 10000, "Sqlite cache size (default is 2000)."); RTABMAP_PARAM(DbSqlite3, CacheSize, unsigned int, 10000,
RTABMAP_PARAM(DbSqlite3, JournalMode, int, 3, "0=DELETE, 1=TRUNCATE, 2=PERSIST, 3=MEMORY, 4=OFF (see sqlite3 doc : \"PRAGMA journal_mode\")"); "PRAGMA cache_size: number of database pages kept in SQLite's page cache (approx. cacheSize * page_size bytes, often ~4 KiB per page). "
RTABMAP_PARAM(DbSqlite3, Synchronous, int, 0, "0=OFF, 1=NORMAL, 2=FULL (see sqlite3 doc : \"PRAGMA synchronous\")"); "Larger values reduce disk I/O when the working set fits in RAM. SQLite built-in default is typically 2000 pages.");
RTABMAP_PARAM(DbSqlite3, TempStore, int, 2, "0=DEFAULT, 1=FILE, 2=MEMORY (see sqlite3 doc : \"PRAGMA temp_store\")"); RTABMAP_PARAM(DbSqlite3, JournalMode, int, 3,
"PRAGMA journal_mode: rollback journal storage. See sqlite.org/pragma.html#pragma_journal_mode for more details. "
"0=DELETE (SQLite default): journal file deleted after each commit. "
"1=TRUNCATE: journal truncated to zero length. "
"2=PERSIST: journal file kept, header zeroed after commit. "
"3=MEMORY: journal in RAM only; faster, weaker crash safety. "
"4=OFF: no journal; fastest, risk of corruption on crash.");
RTABMAP_PARAM(DbSqlite3, Synchronous, int, 0,
"PRAGMA synchronous: how aggressively SQLite syncs the database to disk. See sqlite.org/pragma.html#pragma_synchronous for more details. "
"0=OFF: no wait for persistent storage; fastest, corruption possible on power loss. "
"1=NORMAL: sync at critical moments (common SQLite default with WAL). "
"2=FULL (SQLite safest default): sync after every commit; slowest.");
RTABMAP_PARAM(DbSqlite3, TempStore, int, 2,
"PRAGMA temp_store: where SQLite stores temporary tables and indices. See sqlite.org/pragma.html#pragma_temp_store for more details. "
"0=DEFAULT: SQLite compile-time default (often on-disk temp files). "
"1=FILE: temporary files in the system temp directory. "
"2=MEMORY: temporary data in RAM when possible.");
RTABMAP_PARAM_STR(Db, TargetVersion, "", "Target database version for backward compatibility purpose. Only Major and minor versions are used and should be set (e.g., 0.19 vs 0.20 or 1.0 vs 2.0). Patch version is ignored (e.g., 0.20.1 and 0.20.3 will generate a 0.20 database)."); RTABMAP_PARAM_STR(Db, TargetVersion, "", "Target database version for backward compatibility purpose. Only Major and minor versions are used and should be set (e.g., 0.19 vs 0.20 or 1.0 vs 2.0). Patch version is ignored (e.g., 0.20.1 and 0.20.3 will generate a 0.20 database).");
// Keypoints descriptors/detectors // Keypoints descriptors/detectors
+5
View File
@@ -126,6 +126,11 @@ add_executable(test_dbdriver test_dbdriver.cpp)
target_link_libraries(test_dbdriver gtest_main rtabmap_core) target_link_libraries(test_dbdriver gtest_main rtabmap_core)
add_test(NAME test_dbdriver COMMAND test_dbdriver) add_test(NAME test_dbdriver COMMAND test_dbdriver)
#DBDriverSqlite3.h
add_executable(test_dbdriversqlite3 test_dbdriversqlite3.cpp)
target_link_libraries(test_dbdriversqlite3 gtest_main rtabmap_core)
add_test(NAME test_dbdriversqlite3 COMMAND test_dbdriversqlite3)
#Signature.h #Signature.h
add_executable(test_signature test_signature.cpp) add_executable(test_signature test_signature.cpp)
target_link_libraries(test_signature gtest_main rtabmap_core) target_link_libraries(test_signature gtest_main rtabmap_core)
+175
View File
@@ -0,0 +1,175 @@
#include <gtest/gtest.h>
#include <rtabmap/core/DBDriver.h>
#include <rtabmap/core/DBDriverSqlite3.h>
#include <rtabmap/core/Signature.h>
#include <rtabmap/core/Parameters.h>
#include <rtabmap/utilite/UFile.h>
#include <rtabmap/utilite/UConversion.h>
using namespace rtabmap;
namespace {
std::string uniqueDbPath()
{
static int counter = 0;
return uFormat("/tmp/rtabmap_dbdriversqlite3_test_%d_%d.db", getpid(), ++counter);
}
class DBDriverSqlite3Fixture : public ::testing::Test
{
protected:
void SetUp() override
{
dbPath_ = uniqueDbPath();
driver_ = new DBDriverSqlite3();
ASSERT_TRUE(driver_->openConnection(dbPath_, true));
}
void TearDown() override
{
if(driver_)
{
driver_->closeConnection(false);
delete driver_;
driver_ = nullptr;
}
if(!dbPath_.empty())
{
UFile::erase(dbPath_.c_str());
}
}
void saveSignature(Signature * s)
{
driver_->asyncSave(s);
driver_->emptyTrashes(false);
}
std::string dbPath_;
DBDriverSqlite3 * driver_ = nullptr;
};
} // namespace
TEST(DBDriverSqlite3Test, CreateFactoryReturnsSqliteDriver)
{
DBDriver * driver = DBDriver::create();
ASSERT_NE(driver, nullptr);
EXPECT_NE(dynamic_cast<DBDriverSqlite3 *>(driver), nullptr);
driver->closeConnection(false);
delete driver;
}
TEST(DBDriverSqlite3Test, EmptyUrlIsInMemory)
{
DBDriverSqlite3 driver;
ASSERT_TRUE(driver.openConnection(""));
EXPECT_TRUE(driver.isInMemory());
EXPECT_TRUE(driver.isConnected());
EXPECT_FALSE(driver.getDatabaseVersion().empty());
driver.closeConnection(false);
}
TEST(DBDriverSqlite3Test, FileBackedIsNotInMemory)
{
const std::string path = uniqueDbPath();
DBDriverSqlite3 driver;
ASSERT_TRUE(driver.openConnection(path, true));
EXPECT_FALSE(driver.isInMemory());
EXPECT_EQ(driver.getUrl(), path);
driver.closeConnection(false);
UFile::erase(path.c_str());
}
TEST(DBDriverSqlite3Test, ParseParametersEnablesInMemory)
{
const std::string path = uniqueDbPath();
ParametersMap params;
params.insert(ParametersPair(Parameters::kDbSqlite3InMemory(), "true"));
DBDriverSqlite3 driver(params);
ASSERT_TRUE(driver.openConnection(path, true));
EXPECT_TRUE(driver.isInMemory());
EXPECT_TRUE(driver.isConnected());
driver.asyncSave(new Signature(1));
driver.emptyTrashes(false);
EXPECT_EQ(driver.getTotalNodesSize(), 1);
driver.closeConnection(false);
UFile::erase(path.c_str());
}
TEST(DBDriverSqlite3Test, InMemorySaveToFileOnClose)
{
const std::string path = uniqueDbPath();
ParametersMap params;
params.insert(ParametersPair(Parameters::kDbSqlite3InMemory(), "true"));
DBDriverSqlite3 driver(params);
ASSERT_TRUE(driver.openConnection(path, true));
EXPECT_TRUE(driver.isInMemory());
driver.asyncSave(new Signature(1, 5, 1, 50.0, "sqlite_mem", Transform(1.f, 0.f, 0.f, 0.f, 0.f, 0.f)));
driver.emptyTrashes(false);
driver.closeConnection(true, path);
DBDriverSqlite3 driver2;
ASSERT_TRUE(driver2.openConnection(path));
EXPECT_FALSE(driver2.isInMemory());
Signature * loaded = driver2.loadSignature(1);
ASSERT_NE(loaded, nullptr);
EXPECT_EQ(loaded->getLabel(), "sqlite_mem");
delete loaded;
driver2.closeConnection(false);
UFile::erase(path.c_str());
}
TEST_F(DBDriverSqlite3Fixture, SetPragmasWhileConnected)
{
EXPECT_NO_THROW(driver_->setCacheSize(4000));
EXPECT_NO_THROW(driver_->setJournalMode(1));
EXPECT_NO_THROW(driver_->setSynchronous(1));
EXPECT_NO_THROW(driver_->setTempStore(2));
EXPECT_TRUE(driver_->isConnected());
}
TEST_F(DBDriverSqlite3Fixture, SaveAndLoadSignature)
{
saveSignature(new Signature(1, 5, 7, 100.0, "node1", Transform(1.f, 2.f, 3.f, 0.f, 0.f, 0.f)));
EXPECT_EQ(driver_->getTotalNodesSize(), 1);
Signature * loaded = driver_->loadSignature(1);
ASSERT_NE(loaded, nullptr);
EXPECT_EQ(loaded->id(), 1);
EXPECT_EQ(loaded->getLabel(), "node1");
EXPECT_EQ(loaded->getWeight(), 7);
delete loaded;
}
TEST_F(DBDriverSqlite3Fixture, ReopenPreservesData)
{
saveSignature(new Signature(1, 5, 3, 50.0, "persist", Transform(0.5f, 0.f, 0.f, 0.f, 0.f, 0.f)));
const std::string path = dbPath_;
driver_->closeConnection(true);
delete driver_;
driver_ = nullptr;
driver_ = new DBDriverSqlite3();
ASSERT_TRUE(driver_->openConnection(path));
Signature * loaded = driver_->loadSignature(1);
ASSERT_NE(loaded, nullptr);
EXPECT_EQ(loaded->getLabel(), "persist");
delete loaded;
}
TEST_F(DBDriverSqlite3Fixture, ExecuteNoResultPragma)
{
EXPECT_NO_THROW(driver_->executeNoResult("PRAGMA cache_size=8000;"));
EXPECT_TRUE(driver_->isConnected());
}