Files
sqlitebrowser/src/RowLoader.h
Martin Kleusberg a6d48f1ae4 Simplify interface and implementation of SqliteTableModel
This simplifies the usage and the implementation of the SqliteTableModel
a bit by making the two operating modes it supports (manual query and
interactive query) more obvious in its public interface as well as
simplifying the control flow in the private implementation.
2021-01-25 18:13:49 +01:00

125 lines
3.1 KiB
C++

#ifndef ROW_LOADER_H
#define ROW_LOADER_H
#include <condition_variable>
#include <mutex>
#include <atomic>
#include <memory>
#include <future>
#include <functional>
#include <vector>
#include <QThread>
#include <QString>
#include "RowCache.h"
struct sqlite3;
class RowLoader : public QThread
{
Q_OBJECT
void run() override;
public:
using Cache = RowCache<std::vector<QByteArray>>;
/// set up worker thread to handle row loading
explicit RowLoader (
std::function<std::shared_ptr<sqlite3>(void)> db_getter,
std::function<void(QString)> statement_logger,
std::vector<std::string> & headers,
std::mutex & cache_mutex,
Cache & cache_data
);
void setQuery (const QString& new_query, const QString& newCountQuery = QString());
void triggerRowCountDetermination (int token);
/// trigger asynchronous reading of specified row range,
/// cancelling previous tasks; 'row_end' is exclusive; \param
/// token is eventually returned through the 'fetched'
/// signal. depending on how and when tasks are cancelled, not
/// every triggerFetch() will result in a 'fetched' signal, or the
/// 'fetched' signal may be for a narrower row range.
void triggerFetch (int token, size_t row_begin, size_t row_end);
/// cancel everything
void cancel ();
/// cancel everything and terminate worker thread
void stop ();
/// currently reading any data, or anything in "queue"?
bool readingData () const;
/// wait until not reading any data
void waitUntilIdle () const;
/// get current database - note that the worker thread might be
/// working on it, too... \returns current db, or nullptr.
std::shared_ptr<sqlite3> getDb () const;
signals:
void fetched(int token, size_t row_begin, size_t row_end);
void rowCountComplete(int token, int num_rows);
private:
const std::function<std::shared_ptr<sqlite3>()> db_getter;
const std::function<void(QString)> statement_logger;
std::vector<std::string> & headers;
std::mutex & cache_mutex;
Cache & cache_data;
mutable std::mutex m;
mutable std::condition_variable cv;
QString query;
QString countQuery;
mutable std::future<void> row_counter;
bool first_chunk_loaded;
size_t num_tasks;
std::shared_ptr<sqlite3> pDb; //< exclusive access while held...
bool stop_requested;
struct Task
{
RowLoader & row_loader;
int token;
size_t row_begin;
size_t row_end; //< exclusive
std::atomic<bool> cancel;
Task(RowLoader & row_loader_, int t, size_t a, size_t b)
: row_loader(row_loader_), token(t), row_begin(a), row_end(b), cancel(false)
{
row_loader.num_tasks++;
}
~Task()
{
// (... mutex being held ...)
row_loader.nosync_taskDone();
}
};
std::unique_ptr<Task> current_task;
std::unique_ptr<Task> next_task;
int countRows () const;
void process (Task &);
void nosync_ensureDbAccess ();
void nosync_taskDone ();
};
#endif // ROW_LOADER_H