diff --git a/.gitmodules b/.gitmodules
index 94e1d37..dfd4a5f 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -7,3 +7,9 @@
[submodule "lib/better-enums"]
path = lib/better-enums
url = https://github.com/aantron/better-enums
+[submodule "lib/duckhandy"]
+ path = lib/duckhandy
+ url = https://github.com/KingDuckZ/duckhandy.git
+[submodule "lib/incredis"]
+ path = lib/incredis
+ url = ../incredis.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e556a1d..c9b1531 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -21,6 +21,7 @@ include(gccversion)
include(CPack)
include(CTest)
include(timestamp)
+include(shared_git_project)
option(DINDEXER_DEBUG_CFG_FILE "Enable to set the config file path to the build path" OFF)
option(DINDEXER_WITH_MEDIA_AUTODETECT "Enable code that tries to autodetect the media type and sets --type automatically" ON)
@@ -57,7 +58,7 @@ if ("${DINDEXER_CONFIG_FILE}" STREQUAL "")
endif()
message(STATUS "Config file set to \"${DINDEXER_CONFIG_FILE}\"")
-find_package(Boost 1.53.0 REQUIRED COMPONENTS program_options)
+find_package(Boost 1.53.0 REQUIRED COMPONENTS program_options filesystem system)
find_package(PostgreSQL 8.3 REQUIRED)
find_package(YamlCpp 0.5.1 REQUIRED)
import_libpqtypes_project("${PostgreSQL_INCLUDE_DIRS}" "-O3 ${march_flag}")
@@ -87,7 +88,6 @@ configure_file(
target_include_directories(${PROJECT_NAME} SYSTEM
INTERFACE ${Boost_INCLUDE_DIRS}
- INTERFACE ${PostgreSQL_INCLUDE_DIRS}
)
target_compile_features(${PROJECT_NAME}
@@ -128,29 +128,35 @@ add_subdirectory(src/common)
add_subdirectory(src/machinery)
add_subdirectory(lib/pbl)
add_subdirectory(lib/glob2regex)
+add_subdirectory(src/backends)
+add_subdirectory(src/core)
+add_shared_git_project(lib/duckhandy)
+add_shared_git_project(lib/incredis EXCLUDE_FROM_ALL)
#Actions
add_subdirectory(src/main)
add_subdirectory(src/scan)
add_subdirectory(src/delete)
-add_subdirectory(src/query)
+#add_subdirectory(src/query)
add_subdirectory(src/locate)
add_subdirectory(src/navigate)
add_subdirectory(src/tag)
#Tests
if (BUILD_TESTING)
- add_subdirectory(test/gtest)
+ add_shared_git_project(test/gtest)
add_subdirectory(test/unit)
add_subdirectory(test/unit_cli)
endif()
target_link_libraries(${PROJECT_NAME}
- INTERFACE ${PostgreSQL_LIBRARIES}
INTERFACE ${Boost_LIBRARIES}
INTERFACE ${bare_name}-pq
INTERFACE ${bare_name}-inc
)
+target_link_libraries(${bare_name}-inc
+ INTERFACE duckhandy
+)
target_compile_definitions(${PROJECT_NAME}
INTERFACE WITH_PROGRESS_FEEDBACK
diff --git a/README.md b/README.md
index ab02929..11fff34 100644
--- a/README.md
+++ b/README.md
@@ -168,8 +168,6 @@ and the following libraries:
* **machinery** the bulk of dindexer, such as the indexing functionality
* **pq** a c++ wrapper for libpq (PostgreSql)
-Additionally inside include/helpers/ you will find header-only implementations of very generic helper tools.
-
Currently, actions are just the command line frontend to access the functionalities in the libraries. This way writing a new CLI or GUI should be relatively easy.
This structure might change in the future.
diff --git a/cmake/Modules/shared_git_project.cmake b/cmake/Modules/shared_git_project.cmake
new file mode 100644
index 0000000..54463ef
--- /dev/null
+++ b/cmake/Modules/shared_git_project.cmake
@@ -0,0 +1,110 @@
+# This is free and unencumbered software released into the public domain.
+#
+# Anyone is free to copy, modify, publish, use, compile, sell, or
+# distribute this software, either in source code form or as a compiled
+# binary, for any purpose, commercial or non-commercial, and by any
+# means.
+#
+# In jurisdictions that recognize copyright laws, the author or authors
+# of this software dedicate any and all copyright interest in the
+# software to the public domain. We make this dedication for the benefit
+# of the public at large and to the detriment of our heirs and
+# successors. We intend this dedication to be an overt act of
+# relinquishment in perpetuity of all present and future rights to this
+# software under copyright law.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+# For more information, please refer to
+
+cmake_minimum_required(VERSION 2.8.12.2 FATAL_ERROR)
+
+function (add_shared_git_project SUBMODULE_PATH)
+ if (IS_ABSOLUTE "${SUBMODULE_PATH}")
+ set(submod_path "${SUBMODULE_PATH}")
+ else()
+ set(submod_path "${CMAKE_CURRENT_SOURCE_DIR}/${SUBMODULE_PATH}")
+ endif()
+
+ if (NOT EXISTS "${submod_path}")
+ message(FATAL_ERROR "Path \"${submod_path}\" doesn't exist")
+ endif()
+ if (NOT IS_DIRECTORY "${submod_path}")
+ message(FATAL_ERROR "Path \"${submod_path}\" is not a valid directory")
+ endif()
+
+ if (NOT EXISTS "${submod_path}/.git")
+ message(FATAL_ERROR ".git not found in \"${submod_path}\". Not a git submodule?")
+ endif()
+ if (IS_DIRECTORY "${submod_path}/.git")
+ message(FATAL_ERROR "\"${submod_path}.git\" is a directory, not a file as expected. Not a git submodule?")
+ endif()
+
+ get_filename_component(proj_name_orig "${submod_path}" NAME)
+ if ("${proj_name_orig}" STREQUAL "")
+ message(FATAL_ERROR "Couldn't make up a name for given project in \"${submod_path}\"")
+ endif()
+
+ string(MAKE_C_IDENTIFIER "${proj_name_orig}" proj_name_c_id)
+ string(TOUPPER ${proj_name_c_id} proj_name)
+
+ get_property(shared_projects_list GLOBAL PROPERTY SHARED_PROJECTS_LIST)
+ list(FIND shared_projects_list ${proj_name} found_index)
+ if (${found_index} GREATER -1)
+ #nothing to do, the variable is already set so the project must have been
+ #included already
+ return()
+ endif()
+
+ #Obtain the path to the working tree
+ # see http://stackoverflow.com/questions/27379818/git-possible-to-use-same-submodule-working-copy-by-multiple-projects
+ # git rev-parse --git-dir --show-toplevel
+ execute_process(
+ COMMAND git rev-parse --show-toplevel
+ WORKING_DIRECTORY "${submod_path}"
+ OUTPUT_VARIABLE matched_gitdir
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+
+ #Make sure we got an absolute path
+ if (IS_ABSOLUTE "${matched_gitdir}")
+ set(reported_submodule_dir "${matched_gitdir}")
+ else()
+ file(RELATIVE_PATH reported_submodule_dir "${CMAKE_CURRENT_SOURCE_DIR}" "${submod_path}/${matched_gitdir}")
+ endif()
+ unset(matched_gitdir)
+
+ #Check if submodule is a subdirectory of the current source dir
+ file(RELATIVE_PATH reported_submodule_rel_path "${CMAKE_CURRENT_SOURCE_DIR}" "${reported_submodule_dir}")
+ string(LENGTH "${reported_submodule_rel_path}" rel_path_len)
+ if (${rel_path_len} GREATER 2)
+ string(SUBSTRING "${reported_submodule_rel_path}" 0 3 first_bit)
+ if ("../" STREQUAL "${first_bit}")
+ set(is_out_of_dirtree ON)
+ else()
+ set(is_out_of_dirtree OFF)
+ endif()
+ unset(first_bit)
+ else()
+ set(is_out_of_dirtree OFF)
+ endif()
+ unset(rel_path_len)
+
+ #Globally mark current submodule as handled
+ set_property(GLOBAL APPEND PROPERTY SHARED_PROJECTS_LIST ${proj_name})
+
+ set(shared_project_binary "${CMAKE_CURRENT_BINARY_DIR}/shared_projects/${proj_name_orig}")
+ if (is_out_of_dirtree)
+ #message(FATAL_ERROR "Would call add_subdirectory(\"${reported_submodule_dir}\" \"${shared_project_binary}\")")
+ add_subdirectory("${reported_submodule_dir}" "${shared_project_binary}")
+ else()
+ #message(FATAL_ERROR "Would call add_subdirectory(\"${reported_submodule_rel_path}\")")
+ add_subdirectory("${reported_submodule_rel_path}")
+ endif()
+endfunction()
diff --git a/dindexer.sql.in b/dindexer.sql.in
index 26e0b0b..c2d893a 100644
--- a/dindexer.sql.in
+++ b/dindexer.sql.in
@@ -5,7 +5,7 @@
-- Dumped from database version 9.5.2
-- Dumped by pg_dump version 9.5.2
--- Started on 2016-05-18 00:47:01 CEST
+-- Started on 2016-06-03 20:30:32 CEST
SET statement_timeout = 0;
SET lock_timeout = 0;
@@ -160,6 +160,8 @@ CREATE TABLE sets (
creation timestamp with time zone DEFAULT now() NOT NULL,
app_name character varying NOT NULL,
content_type character(1) DEFAULT 'G'::bpchar NOT NULL,
+ disk_label text NOT NULL,
+ fs_uuid text NOT NULL,
CONSTRAINT chk_sets_type CHECK (((type = 'C'::bpchar) OR (type = 'D'::bpchar) OR (type = 'V'::bpchar) OR (type = 'B'::bpchar) OR (type = 'F'::bpchar) OR (type = 'H'::bpchar) OR (type = 'Z'::bpchar) OR (type = 'O'::bpchar)))
);
@@ -309,7 +311,7 @@ GRANT ALL ON SCHEMA public TO postgres;
GRANT ALL ON SCHEMA public TO PUBLIC;
--- Completed on 2016-05-18 00:47:01 CEST
+-- Completed on 2016-06-03 20:30:33 CEST
--
-- PostgreSQL database dump complete
diff --git a/dindexer.yml b/dindexer.yml
index 1d3b7a9..eeb1a26 100644
--- a/dindexer.yml
+++ b/dindexer.yml
@@ -1,8 +1,21 @@
%YAML 1.2
---
-db_settings:
- username: your_username
- password: your_password
- dbname: dindexer
- port: 5432
- address: 200.100.200.100
+backend_name: postgresql
+postgresql_settings:
+ connection:
+ username: your_username
+ password: your_password
+ dbname: dindexer
+ port: 5432
+ address: 200.100.200.100
+
+redis_settings:
+ connection:
+ address: 200.100.200.100
+ port: 6379
+
+ script_paths:
+ - /home/duckz/dev/build/dindexer/Debug/src/backends/redis/lua
+ - /home/duckz/dev/build/dindexer/Release/src/backends/redis/lua
+
+backend_paths: path to your build_dir/src/backend
diff --git a/docs/hiredis_libev_multithread.md b/docs/hiredis_libev_multithread.md
new file mode 100644
index 0000000..c86602f
--- /dev/null
+++ b/docs/hiredis_libev_multithread.md
@@ -0,0 +1,166 @@
+[TOC]
+
+# Using hiredis+libev in a separate thread for events
+
+Used sources:
+
+1. [stackoverflow.com/questions/14621261][link_so_1]
+2. [stackoverflow.com/questions/8611126][link_so_2]
+3. [libev thread locking example][link_ev_doc]
+
+
+## Explanation
+
+### Link 1
+
+Possibly due to the original question asked, [Link 1][link_so_1] seems to show that you need to have at least two ev_loop objects created in order to run one in a separate thread. The code on that page:
+
+```cpp
+//This program is demo for using pthreads with libev.
+//Try using Timeout values as large as 1.0 and as small as 0.000001
+//and notice the difference in the output
+
+//(c) 2009 debuguo
+//(c) 2013 enthusiasticgeek for stack overflow
+//Free to distribute and improve the code. Leave credits intact
+
+#include
+#include // for puts
+#include
+#include
+
+pthread_mutex_t lock;
+double timeout = 0.00001;
+ev_timer timeout_watcher;
+int timeout_count = 0;
+
+ev_async async_watcher;
+int async_count = 0;
+
+struct ev_loop* loop2;
+
+void* loop2thread(void* args)
+{
+ printf("Inside loop 2"); // Here one could initiate another timeout watcher
+ ev_loop(loop2, 0); // similar to the main loop - call it say timeout_cb1
+ return NULL;
+}
+
+static void async_cb (EV_P_ ev_async *w, int revents)
+{
+ //puts ("async ready");
+ pthread_mutex_lock(&lock); //Don't forget locking
+ ++async_count;
+ printf("async = %d, timeout = %d \n", async_count, timeout_count);
+ pthread_mutex_unlock(&lock); //Don't forget unlocking
+}
+
+static void timeout_cb (EV_P_ ev_timer *w, int revents) // Timer callback function
+{
+ //puts ("timeout");
+ if (ev_async_pending(&async_watcher)==false) { //the event has not yet been processed (or even noted) by the event loop? (i.e. Is it serviced? If yes then proceed to)
+ ev_async_send(loop2, &async_watcher); //Sends/signals/activates the given ev_async watcher, that is, feeds an EV_ASYNC event on the watcher into the event loop.
+ }
+
+ pthread_mutex_lock(&lock); //Don't forget locking
+ ++timeout_count;
+ pthread_mutex_unlock(&lock); //Don't forget unlocking
+ w->repeat = timeout;
+ ev_timer_again(loop, &timeout_watcher); //Start the timer again.
+}
+
+int main (int argc, char** argv)
+{
+ if (argc < 2) {
+ puts("Timeout value missing.\n./demo ");
+ return -1;
+ }
+ timeout = atof(argv[1]);
+
+ struct ev_loop *loop = EV_DEFAULT; //or ev_default_loop (0);
+
+ //Initialize pthread
+ pthread_mutex_init(&lock, NULL);
+ pthread_t thread;
+
+ // This loop sits in the pthread
+ loop2 = ev_loop_new(0);
+
+ //This block is specifically used pre-empting thread (i.e. temporary interruption and suspension of a task, without asking for its cooperation, with the intention to resume that task later.)
+ //This takes into account thread safety
+ ev_async_init(&async_watcher, async_cb);
+ ev_async_start(loop2, &async_watcher);
+ pthread_create(&thread, NULL, loop2thread, NULL);
+
+ ev_timer_init (&timeout_watcher, timeout_cb, timeout, 0.); // Non repeating timer. The timer starts repeating in the timeout callback function
+ ev_timer_start (loop, &timeout_watcher);
+
+ // now wait for events to arrive
+ ev_loop(loop, 0);
+ //Wait on threads for execution
+ pthread_join(thread, NULL);
+
+ pthread_mutex_destroy(&lock);
+ return 0;
+}
+```
+
+with the comment *"Note for libev 4+ ev_loop should be ev_run."* is still slightly useful but it shouldn't be taken as a model.
+
+
+### Link 2
+
+The [second link][link_so_2] is what shows that one ev_loop is enough. This is the code provided by the original poster:
+
+```cpp
+ void RedisSubscriber::Start() {
+ m_redis = redisAsyncConnect(m_addr.c_str(),m_port);
+ m_redis->data = (void*)this;
+
+ m_loop = ev_loop_new(EVFLAG_NOINOTIFY);
+ redisLibevAttach(m_loop, m_redis);
+ redisAsyncSetConnectCallback(m_redis,connectCallback);
+ redisAsyncSetDisconnectCallback(m_redis,disconnectCallback);
+ redisAsyncCommand(m_redis, subscribeCallback, NULL, "SUBSCRIBE %s", m_channel.c_str());
+
+ m_thread = boost::thread(ev_loop,m_loop,0);
+ }
+
+ void RedisSubscriber::Stop() {
+ redisAsyncFree(m_redis);
+ m_thread.join();
+ m_redis = 0;
+ }
+
+ void RedisSubscriber::connectCallback(const redisAsyncContext *c) {
+
+ }
+
+ void RedisSubscriber::disconnectCallback(const redisAsyncContext *c, int status) {
+ RedisSubscriber* r = (RedisSubscriber*)(c->data);
+ ev_unloop(r->m_loop,EVUNLOOP_ALL);
+ }
+
+ void RedisSubscriber::subscribeCallback(redisAsyncContext *c, void *r, void *privdata) {
+
+ }
+```
+
+There are no accepted answers, but the answer from *themoondothshine* provides very useful info. Here is what it says:
+
+Assuming that you mean ev_run for your boost::thread, here's what you can do:
+
+1. Setup an `ev_async`
+2. In the callback of `ev_async` call `ev_break`.
+3. Call `ev_async_send` from `RedisSubscriber::Stop()`. `ev_async` watchers are thread-safe -- it uses memory barriers for synchronising between threads.
+
+This will cause the event loop to stop, and `m_thread.join()` will return.
+
+
+### Link 3
+
+The [THREAD LOCKING EXAMPLE][link_ev_doc] shows how to lock in order to protect the ev_loop object in use.
+
+[link_so_1]: http://stackoverflow.com/questions/14621261/using-libev-with-multiple-threads#14779930
+[link_so_2]: http://stackoverflow.com/questions/8611126/hiredis-libev-and-boostthreads
+[link_ev_doc]: http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#THREAD_LOCKING_EXAMPLE
diff --git a/docs/posts/04_whats_cooking.md b/docs/posts/04_whats_cooking.md
new file mode 100644
index 0000000..2a084d8
--- /dev/null
+++ b/docs/posts/04_whats_cooking.md
@@ -0,0 +1,11 @@
+### What's cooking? ###
+
+It's been roughly a month since I released version 0.1.5b and most of the activity has been on the [dev branch](https://bitbucket.org/King_DuckZ/dindexer/branch/dev) since then. It's still a bit too early to make a new release, but if you want to get a peek at the new features this is the right moment as commit e2275ce should give you a working version of #dindexer.
+
+Most notably, you will have a `tag` command, that will allow you to tag files. You should also be able to list files by tag, using the `dindexer locate --tags ` command.
+
+The less evident change (although that's what took up most of my time) is the separation of the PostgreSQL code from the CL client. You have been asking for Sqlite support, I heard you and I'm getting everything ready so that an Sqlite plugin can be implemented! Currently, PostgreSQL is still the only backend you can choose, so please be patient... or even better, step in and contribute to dindexer! :)
+
+[bitbucket.org/King_DuckZ/dindexer](https://bitbucket.org/King_DuckZ/dindexer)
+
+\#dindexer #linux #opensource #cpp #sqlite
diff --git a/flat_git.yml b/flat_git.yml
new file mode 100644
index 0000000..bf79c81
--- /dev/null
+++ b/flat_git.yml
@@ -0,0 +1,3 @@
+inplace_submodules:
+ - pbl
+ - better-enums
diff --git a/include/backends/backend_loader.hpp b/include/backends/backend_loader.hpp
new file mode 100644
index 0000000..7795d0c
--- /dev/null
+++ b/include/backends/backend_loader.hpp
@@ -0,0 +1,62 @@
+/* Copyright 2015, 2016, Michele Santullo
+ * This file is part of "dindexer".
+ *
+ * "dindexer" 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.
+ *
+ * "dindexer" 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 "dindexer". If not, see .
+ */
+
+#ifndef id756A258A98B24B0DB2529BCEEC5137E2
+#define id756A258A98B24B0DB2529BCEEC5137E2
+
+#include
+#include
+#include
+
+namespace YAML {
+ class Node;
+} //namespace YAML
+
+namespace dindb {
+ class Backend;
+
+ using BackendPtr = std::unique_ptr;
+
+ class BackendPlugin {
+ public:
+ BackendPlugin ( void );
+ BackendPlugin ( BackendPlugin&& ) = default;
+ BackendPlugin ( const std::string& parSOPath, const YAML::Node* parConfig );
+ ~BackendPlugin ( void ) noexcept;
+
+ const boost::string_ref& name ( void ) const;
+ Backend& backend ( void );
+ const Backend& backend ( void ) const;
+ bool is_loaded ( void ) const;
+ int backend_interface_version ( void ) const;
+ int max_supported_interface_version ( void ) const;
+
+ BackendPlugin& operator= ( BackendPlugin&& ) = default;
+
+ private:
+ using SoHandle = std::unique_ptr;
+
+ SoHandle m_lib;
+ BackendPtr m_backend;
+ boost::string_ref m_name;
+ int m_iface_ver;
+ };
+
+ std::string backend_name ( const std::string& parSOPath );
+} //namespace dindb
+
+#endif
diff --git a/include/dindexer-common/cmake_on_off.h b/include/backends/backend_version.hpp
similarity index 65%
rename from include/dindexer-common/cmake_on_off.h
rename to include/backends/backend_version.hpp
index 165ab95..8b31e82 100644
--- a/include/dindexer-common/cmake_on_off.h
+++ b/include/backends/backend_version.hpp
@@ -15,24 +15,11 @@
* along with "dindexer". If not, see .
*/
-#ifndef id9B6B373E88404330ADEE51A4EC861787
-#define id9B6B373E88404330ADEE51A4EC861787
+#ifndef idAA27B58429DB41C2AF53204CC5010E94
+#define idAA27B58429DB41C2AF53204CC5010E94
-#if !defined(CMAKE_ON)
-# define CMAKE_ON 1
-# define CMAKE_on 1
-# define CMAKE_On 1
-# define CMAKE_oN 1
-#endif
-#if !defined(CMAKE_OFF)
-# define CMAKE_OFF 0
-# define CMAKE_OFf 0
-# define CMAKE_OfF 0
-# define CMAKE_Off 0
-# define CMAKE_oFF 0
-# define CMAKE_oFf 0
-# define CMAKE_ofF 0
-# define CMAKE_off 0
-#endif
+namespace dindb {
+ constexpr const int g_current_iface_version = 1;
+} //namespace dindb
#endif
diff --git a/include/backends/db_backend.hpp b/include/backends/db_backend.hpp
new file mode 100644
index 0000000..1ef8ce5
--- /dev/null
+++ b/include/backends/db_backend.hpp
@@ -0,0 +1,91 @@
+/* Copyright 2015, 2016, Michele Santullo
+ * This file is part of "dindexer".
+ *
+ * "dindexer" 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.
+ *
+ * "dindexer" 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 "dindexer". If not, see .
+ */
+
+#ifndef id7506CA9825454B80856154ACFE8A9DE2
+#define id7506CA9825454B80856154ACFE8A9DE2
+
+#include "backends/backend_loader.hpp"
+#include "duckhandy/MaxSizedArray.hpp"
+#include
+#include
+#include
+#include
+#include