Mercurial > hg > orthanc-indexer
view Sources/IndexerDatabase.cpp @ 26:2f410de7715d default tip
added CITATION.cff
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Sat, 06 Apr 2024 17:20:59 +0200 |
parents | ca40236fda57 |
children |
line wrap: on
line source
/** * Indexer plugin for Orthanc * Copyright (C) 2021-2024 Sebastien Jodogne, UCLouvain, Belgium * * 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 3 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, see <http://www.gnu.org/licenses/>. **/ #include "IndexerDatabase.h" #include <EmbeddedResources.h> #include <SQLite/Transaction.h> void IndexerDatabase::AddFileInternal(const std::string& path, const std::time_t time, const uintmax_t size, bool isDicom, const std::string& instanceId) { Orthanc::SQLite::Transaction transaction(db_); transaction.Begin(); Orthanc::SQLite::Statement statement(db_, SQLITE_FROM_HERE, "INSERT INTO Files VALUES(?, ?, ?, ?, ?)"); statement.BindString(0, path); statement.BindInt64(1, time); statement.BindInt64(2, size); statement.BindInt64(3, isDicom); statement.BindString(4, instanceId); statement.Run(); transaction.Commit(); } void IndexerDatabase::Initialize() { { Orthanc::SQLite::Transaction transaction(db_); transaction.Begin(); if (!db_.DoesTableExist("Attachments")) { std::string sql; Orthanc::EmbeddedResources::GetFileResource(sql, Orthanc::EmbeddedResources::PREPARE_DATABASE); db_.Execute(sql); } transaction.Commit(); } // Performance tuning of SQLite with PRAGMAs // http://www.sqlite.org/pragma.html db_.Execute("PRAGMA SYNCHRONOUS=NORMAL;"); db_.Execute("PRAGMA JOURNAL_MODE=WAL;"); db_.Execute("PRAGMA LOCKING_MODE=EXCLUSIVE;"); db_.Execute("PRAGMA WAL_AUTOCHECKPOINT=1000;"); } void IndexerDatabase::Open(const std::string& path) { boost::mutex::scoped_lock lock(mutex_); db_.Open(path); Initialize(); } void IndexerDatabase::OpenInMemory() { boost::mutex::scoped_lock lock(mutex_); db_.OpenInMemory(); Initialize(); } IndexerDatabase::FileStatus IndexerDatabase::LookupFile(std::string& oldInstanceId, const std::string& path, const std::time_t time, const uintmax_t size) { boost::mutex::scoped_lock lock(mutex_); FileStatus result; Orthanc::SQLite::Transaction transaction(db_); transaction.Begin(); { Orthanc::SQLite::Statement statement(db_, SQLITE_FROM_HERE, "SELECT time, size, isDicom, instanceId FROM Files WHERE path=?"); statement.BindString(0, path); if (statement.Step()) { if (time == static_cast<std::time_t>(statement.ColumnInt64(0)) && size == static_cast<uintmax_t>(statement.ColumnInt64(1))) { if (statement.ColumnBool(2)) { result = FileStatus_AlreadyStored; } else { result = FileStatus_NotDicom; } } else { result = FileStatus_Modified; oldInstanceId = statement.ColumnString(3); } } else { result = FileStatus_New; } } transaction.Commit(); return result; } bool IndexerDatabase::RemoveFile(const std::string& path) { boost::mutex::scoped_lock lock(mutex_); Orthanc::SQLite::Transaction transaction(db_); transaction.Begin(); std::string instanceId; { Orthanc::SQLite::Statement statement(db_, SQLITE_FROM_HERE, "SELECT instanceId FROM Files WHERE path=?"); statement.BindString(0, path); if (statement.Step()) { instanceId = statement.ColumnString(0); } else { throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentItem); } } bool isLastInstance; { Orthanc::SQLite::Statement statement(db_, SQLITE_FROM_HERE, "SELECT COUNT(*) FROM Files WHERE instanceId=?"); statement.BindString(0, instanceId); if (statement.Step()) { int64_t count = statement.ColumnInt64(0); if (count == 0) { throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); } else { isLastInstance = (count == 1); } } else { throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); } } { Orthanc::SQLite::Statement statement(db_, SQLITE_FROM_HERE, "DELETE FROM Files WHERE path=?"); statement.BindString(0, path); statement.Run(); } transaction.Commit(); return isLastInstance; } void IndexerDatabase::AddDicomInstance(const std::string& path, const std::time_t time, const uintmax_t size, const std::string& instanceId) { boost::mutex::scoped_lock lock(mutex_); AddFileInternal(path, time, size, true, instanceId); } void IndexerDatabase::AddNonDicomFile(const std::string& path, const std::time_t time, const uintmax_t size) { boost::mutex::scoped_lock lock(mutex_); AddFileInternal(path, time, size, false, ""); } void IndexerDatabase::Apply(IFileVisitor& visitor) { boost::mutex::scoped_lock lock(mutex_); Orthanc::SQLite::Transaction transaction(db_); transaction.Begin(); Orthanc::SQLite::Statement statement(db_, SQLITE_FROM_HERE, "SELECT path, isDicom, instanceId FROM Files"); while (statement.Step()) { visitor.VisitInstance(statement.ColumnString(0), statement.ColumnBool(1), statement.ColumnString(2)); } transaction.Commit(); } bool IndexerDatabase::AddAttachment(const std::string& uuid, const std::string& instanceId) { boost::mutex::scoped_lock lock(mutex_); Orthanc::SQLite::Transaction transaction(db_); transaction.Begin(); { Orthanc::SQLite::Statement statement(db_, SQLITE_FROM_HERE, "SELECT COUNT(*) FROM Files WHERE instanceId=?"); statement.BindString(0, instanceId); if (!statement.Step() || statement.ColumnInt64(0) == 0) { return false; } } { Orthanc::SQLite::Statement statement(db_, SQLITE_FROM_HERE, "INSERT INTO Attachments VALUES(?, ?)"); statement.BindString(0, uuid); statement.BindString(1, instanceId); statement.Run(); } transaction.Commit(); return true; } bool IndexerDatabase::LookupAttachment(std::string& path, const std::string& uuid) { boost::mutex::scoped_lock lock(mutex_); Orthanc::SQLite::Transaction transaction(db_); transaction.Begin(); bool found = true; std::string instanceId; { Orthanc::SQLite::Statement statement(db_, SQLITE_FROM_HERE, "SELECT instanceId FROM Attachments WHERE uuid=?"); statement.BindString(0, uuid); if (statement.Step()) { instanceId = statement.ColumnString(0); } else { found = false; } } if (found) { Orthanc::SQLite::Statement statement(db_, SQLITE_FROM_HERE, "SELECT path FROM Files WHERE instanceId=?"); statement.BindString(0, instanceId); if (statement.Step()) { path = statement.ColumnString(0); } else { found = false; } } transaction.Commit(); return found; } void IndexerDatabase::RemoveAttachment(const std::string& uuid) { boost::mutex::scoped_lock lock(mutex_); Orthanc::SQLite::Transaction transaction(db_); transaction.Begin(); { Orthanc::SQLite::Statement statement(db_, SQLITE_FROM_HERE, "DELETE FROM Attachments WHERE uuid=?"); statement.BindString(0, uuid); statement.Run(); } transaction.Commit(); } unsigned int IndexerDatabase::GetFilesCount() { Orthanc::SQLite::Statement statement(db_, SQLITE_FROM_HERE, "SELECT COUNT(*) FROM Files"); statement.Step(); return static_cast<unsigned int>(statement.ColumnInt64(0)); } unsigned int IndexerDatabase::GetAttachmentsCount() { Orthanc::SQLite::Statement statement(db_, SQLITE_FROM_HERE, "SELECT COUNT(*) FROM Attachments"); statement.Step(); return static_cast<unsigned int>(statement.ColumnInt64(0)); }