coming
天行健 君子以自强不息
记录我的成长
前言
Connection类与Indexer类负责项目的数据库模块。Connection类相当于数据库的服务端;Indexer类相当于数据库的客户端。
Connection类
该类作为数据库服务端,提供管理数据库底层的接口;定义于src/musikcore/db/Connection.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| class Connection { public: DELETE_COPY_AND_ASSIGNMENT_DEFAULTS(Connection)
Connection() noexcept; ~Connection();
int Open(const std::string &database, unsigned int options = 0, unsigned int cache = 0); int Close() noexcept; int Execute(const char* sql); int64_t LastInsertedId() noexcept; int LastModifiedRowCount() noexcept; void Interrupt(); void Checkpoint() noexcept;
private: void Initialize(unsigned int cache); void UpdateReferenceCount(bool init); int StepStatement(sqlite3_stmt *stmt) noexcept;
friend class Statement; friend class ScopedTransaction; int transactionCounter; sqlite3 *connection; std::mutex mutex; };
|
Connection类有两个友元类Statement类(src/musikcore/db/Statement.h)与ScopedTransaction类(src/musikcore/db/ScopedTransaction.h)。ScopedTransaction类是对即时事务的封装,Statement类对应SQL语句。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| class ScopedTransaction { public: DELETE_CLASS_DEFAULTS(ScopedTransaction) ScopedTransaction(Connection &connection); ~ScopedTransaction(); void Cancel() noexcept; void CommitAndRestart();
private: inline void Begin(); inline void End(); Connection *connection; bool canceled; };
class Statement { public: DELETE_CLASS_DEFAULTS(Statement)
Statement(const char* sql, Connection &connection) noexcept; virtual ~Statement() noexcept; void BindInt32(int position, int bindInt) noexcept; void BindInt64(int position, int64_t bindInt) noexcept; void BindFloat(int position, float bindFloat) noexcept; void BindText(int position, const std::string& bindText); void BindNull(int position) noexcept; const int ColumnInt32(int column) noexcept; const int64_t ColumnInt64(int column) noexcept; const float ColumnFloat(int column) noexcept; const char* ColumnText(int column) noexcept; const bool IsNull(int column) noexcept; int Step(); void Reset() noexcept; void Unbind() noexcept; void ResetAndUnbind() noexcept;
private: friend class Connection; Statement(Connection &connection) noexcept; sqlite3_stmt *stmt; Connection *connection; int modifiedRows; };
|
Indexer类
该类作为数据库客户端,提供各种接口用于向数据库服务端发起相应的请求;定义于src/musikcore/db/Indexer.h,继承了类IIndexer、IIndexerWriter与IIndexerNotifier,IIndexerWriter类与IIndexerNotifier类仅声明了一些虚函数,Indexer类将它们实现。因此只额外解析IIndexer类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
| class Indexer : public mymusic::core::IIndexer, public mymusic::core::sdk::IIndexerWriter, public mymusic::core::sdk::IIndexerNotifier { public: Indexer( const std::string& libraryPath, const std::string& dbFilename);
Indexer(const Indexer&) = delete; virtual ~Indexer();
void AddPath(const std::string& path) override; void RemovePath(const std::string& path) override; void GetPaths(std::vector<std::string>& paths) override; void Schedule(SyncType type) override; void Stop() override;
State GetState() noexcept override { return this->state; }
mymusic::core::sdk::ITagStore* CreateWriter() override; bool RemoveByUri(mymusic::core::sdk::IIndexerSource* source, const char* uri) override; bool RemoveByExternalId(mymusic::core::sdk::IIndexerSource* source, const char* id) override; int RemoveAll(mymusic::core::sdk::IIndexerSource* source) override; void CommitProgress(mymusic::core::sdk::IIndexerSource* source, unsigned updatedTracks) override; int GetLastModifiedTime(mymusic::core::sdk::IIndexerSource* source, const char* id) override;
bool Save( mymusic::core::sdk::IIndexerSource* source, mymusic::core::sdk::ITagStore* store, const char* externalId = "") override;
void ScheduleRescan(mymusic::core::sdk::IIndexerSource* source) override;
private: struct AddRemoveContext { bool add{ false }; std::string path; }; struct SyncContext { SyncType type; int sourceId; }; typedef std::vector<std::shared_ptr< mymusic::core::sdk::ITagReader>> TagReaderList; typedef std::vector<std::shared_ptr< mymusic::core::sdk::IDecoderFactory>> DecoderList; typedef std::vector<std::shared_ptr< mymusic::core::sdk::IIndexerSource>> IndexerSourceList; void ThreadLoop(); void Synchronize(const SyncContext& context, boost::asio::io_service* io); void FinalizeSync(const SyncContext& context); void SyncDelete(); void SyncCleanup(); void SyncPlaylistTracksOrder(); mymusic::core::sdk::ScanResult SyncSource( mymusic::core::sdk::IIndexerSource* source, const std::vector<std::string>& paths); void ProcessAddRemoveQueue(); void SyncOptimize(); void RunAnalyzers(); std::set<int> GetOrphanedSourceIds(); int RemoveAllForSourceId(int sourceId); void Schedule(SyncType type, mymusic::core::sdk::IIndexerSource *source); void IncrementTracksScanned(int delta = 1);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
| void SyncDirectory( boost::asio::io_service* io, const std::string& syncRoot, const std::string& currentPath, int64_t pathId); void ReadMetadataFromFile( boost::asio::io_service* io, const boost::filesystem::path& path, const std::string& pathId); bool Bail() noexcept; db::Connection dbConnection; std::string libraryPath; std::string dbFilename; std::atomic<State> state; boost::mutex stateMutex; boost::condition waitCondition; std::unique_ptr<std::thread> thread; std::atomic<int> incrementalUrisScanned, totalUrisScanned; std::deque<AddRemoveContext> addRemoveQueue; std::deque<SyncContext> syncQueue; TagReaderList tagReaders; DecoderList audioDecoders; IndexerSourceList sources; std::shared_ptr<mymusic::core::Preferences> prefs; std::shared_ptr<mymusic::core::db::ScopedTransaction> trackTransaction; std::vector<std::string> paths; std::shared_ptr<mymusic::core::sdk::IIndexerSource> currentSource; };
class IIndexer { public: sigslot::signal0<> Started; sigslot::signal1<int> Finished; sigslot::signal1<int> Progress; enum State { StateIdle = 0, StateIndexing = 1, StateStopping = 2, StateStopped = 3 }; enum class SyncType { All = 0, Local = 1, Rebuild = 2, Sources = 3 };
virtual ~IIndexer() { } virtual void AddPath(const std::string& path) = 0; virtual void RemovePath(const std::string& path) = 0; virtual void GetPaths(std::vector<std::string>& paths) = 0; virtual void Schedule(SyncType type) = 0; virtual void Stop() = 0; virtual State GetState() = 0; };
|
其中,Track类提供对轨道数据的各种读操作接口,TagStore类提供轨道数据的各种写操作接口;
本文代表个人观点,内容仅供参考。若有不恰当之处,望不吝赐教!