diff --git a/.gitignore b/.gitignore index c0b8dbb2d7..8600ed0dc7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,26 @@ +# CLion generated files +cpp/cmake-build-debug/ +cpp/cmake-build-release/ +cpp/cmake_build +cpp/.idea/ + .idea/ .ycm_extra_conf.py __pycache__ +# vscode generated files +.vscode + .env build cmake-build-debug cmake-build-release cmake_build + +# Compiled source +*.a +*.so +*.so.* *.o *.lo *.tar.gz diff --git a/CHANGELOGS.md b/CHANGELOGS.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpp/CHANGELOG.md b/cpp/CHANGELOG.md new file mode 100644 index 0000000000..2080fec550 --- /dev/null +++ b/cpp/CHANGELOG.md @@ -0,0 +1,16 @@ +# Changelog + +Please mark all change in change log and use the ticket from JIRA. + +## [Unreleased] + +### Bug + +### Improvement + +### New Feature + +### Task + +- MS-1 - Add CHANGELOG.md +- MS-4 - Refactor the vecwise_engine code structure \ No newline at end of file diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 00a206484f..6fcb31a257 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -4,10 +4,32 @@ # Proprietary and confidential. #------------------------------------------------------------------------------- -cmake_minimum_required(VERSION 3.12) +cmake_minimum_required(VERSION 3.14) +message(STATUS "Building using CMake version: ${CMAKE_VERSION}") +set(MEGASEARCH_VERSION "0.1.0") + +string(REGEX MATCH "^[0-9]+\\.[0-9]+\\.[0-9]+" MEGASEARCH_BASE_VERSION "${MEGASEARCH_VERSION}") + +project(megasearch VERSION "${MEGASEARCH_BASE_VERSION}") project(vecwise_engine LANGUAGES CUDA CXX) +set(MEGASEARCH_VERSION_MAJOR "${megasearch_VERSION_MAJOR}") +set(MEGASEARCH_VERSION_MINOR "${megasearch_VERSION_MINOR}") +set(MEGASEARCH_VERSION_PATCH "${megasearch_VERSION_PATCH}") + +if(MEGASEARCH_VERSION_MAJOR STREQUAL "" + OR MEGASEARCH_VERSION_MINOR STREQUAL "" + OR MEGASEARCH_VERSION_PATCH STREQUAL "") + message(FATAL_ERROR "Failed to determine MegaSearch version from '${MEGASEARCH_VERSION}'") +endif() + +message(STATUS "MegaSearch version: " + "${MEGASEARCH_VERSION_MAJOR}.${MEGASEARCH_VERSION_MINOR}.${MEGASEARCH_VERSION_PATCH} " + "(full: '${MEGASEARCH_VERSION}')") + +set(MEGASEARCH_SOURCE_DIR ${PROJECT_SOURCE_DIR}) +set(MEGASEARCH_BINARY_DIR ${PROJECT_BINARY_DIR}) find_package(CUDA) set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS} -Xcompiler -fPIC -std=c++11 -D_FORCE_INLINES -arch sm_60 --expt-extended-lambda") set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS} -O0 -g") @@ -32,16 +54,6 @@ else() set(VECWISE_BUILD_ARCH unknown) endif() -if(DEFINED UNIX) - message("building vecwise on Unix") - set(VECWISE_BUILD_SYSTEM macos) -elseif(DEFINED APPLE) - message("building vecwise on MacOS") - set(VECWISE_BUILD_SYSTEM unix) -else() - message("unknown OS") - set(VECWISE_BUILD_SYSTEM unknown) -endif () if(CMAKE_BUILD_TYPE STREQUAL "Release") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -fPIC -DELPP_THREAD_SAFE") @@ -54,7 +66,19 @@ if (GPU_VERSION STREQUAL "ON") add_definitions("-DENABLE_LICENSE") endif () -set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/" ${CMAKE_MODULE_PATH}) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +if (BUILD_UNIT_TEST) + option(MEGASEARCH_BUILD_TESTS "Build the megasearch test suite" ON) +endif(BUILD_UNIT_TEST) + +include(ExternalProject) +include(ThirdPartyPackages) + +include_directories(${MEGASEARCH_SOURCE_DIR}) +link_directories(${MEGASEARCH_BINARY_DIR}) + +## Following should be check set(VECWISE_ENGINE_INCLUDE ${PROJECT_SOURCE_DIR}/include) set(VECWISE_ENGINE_SRC ${PROJECT_SOURCE_DIR}/src) @@ -73,6 +97,7 @@ link_directories(${VECWISE_THIRD_PARTY_BUILD}/lib64) #execute_process(COMMAND bash build.sh # WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/third_party) + add_subdirectory(src) add_subdirectory(test_client) diff --git a/cpp/build.sh b/cpp/build.sh index f03b411bbb..fde83360ba 100755 --- a/cpp/build.sh +++ b/cpp/build.sh @@ -4,8 +4,9 @@ BUILD_TYPE="Debug" BUILD_UNITTEST="off" BUILD_GPU="OFF" INSTALL_PREFIX=$(pwd)/megasearch +MAKE_CLEAN="OFF" -while getopts "p:t:uhg" arg +while getopts "p:t:uhgr" arg do case $arg in t) @@ -21,6 +22,12 @@ do g) BUILD_GPU="ON" ;; + r) + if [[ -d cmake_build ]]; then + rm ./cmake_build -r + MAKE_CLEAN="ON" + fi + ;; h) # help echo " @@ -28,9 +35,11 @@ parameter: -t: build type -u: building unit test options -p: install prefix +-g: build GPU version +-r: remove previous build directory usage: -./build.sh -t \${BUILD_TYPE} [-u] [-h] +./build.sh -t \${BUILD_TYPE} [-u] [-h] [-g] [-r] " exit 0 ;; @@ -41,27 +50,29 @@ usage: esac done -if [[ -d cmake_build ]]; then - rm cmake_build -r +if [[ ! -d cmake_build ]]; then + mkdir cmake_build + MAKE_CLEAN="ON" fi -rm -rf ./cmake_build -mkdir cmake_build cd cmake_build CUDA_COMPILER=/usr/local/cuda/bin/nvcc -CMAKE_CMD="cmake -DBUILD_UNIT_TEST=${BUILD_UNITTEST} \ --DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} --DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ --DCMAKE_CUDA_COMPILER=${CUDA_COMPILER} \ --DGPU_VERSION=${BUILD_GPU} \ -$@ ../" -echo ${CMAKE_CMD} +if [[ ${MAKE_CLEAN} = "ON" ]]; then + CMAKE_CMD="cmake -DBUILD_UNIT_TEST=${BUILD_UNITTEST} \ + -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} + -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ + -DCMAKE_CUDA_COMPILER=${CUDA_COMPILER} \ + -DGPU_VERSION=${BUILD_GPU} \ + $@ ../" + echo ${CMAKE_CMD} -${CMAKE_CMD} + ${CMAKE_CMD} + make clean +fi -make clean && make -j || exit 1 +make -j || exit 1 if [[ ${BUILD_TYPE} != "Debug" ]]; then strip src/vecwise_server diff --git a/cpp/cmake/GoogleTest.cmake b/cpp/cmake/GoogleTest.cmake new file mode 100644 index 0000000000..9ea62af1c4 --- /dev/null +++ b/cpp/cmake/GoogleTest.cmake @@ -0,0 +1,92 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Tries to find GTest headers and libraries. +# +# Usage of this module as follows: +# +# find_package(GTest) +# +# Variables used by this module, they can change the default behaviour and need +# to be set before calling find_package: +# +# GTest_HOME - When set, this path is inspected instead of standard library +# locations as the root of the GTest installation. +# The environment variable GTEST_HOME overrides this veriable. +# +# This module defines +# GTEST_INCLUDE_DIR, directory containing headers +# GTEST_LIBS, directory containing gtest libraries +# GTEST_STATIC_LIB, path to libgtest.a +# GTEST_SHARED_LIB, path to libgtest's shared library +# GTEST_FOUND, whether gtest has been found + +if( NOT "${GTEST_HOME}" STREQUAL "") + file( TO_CMAKE_PATH "${GTEST_HOME}" _native_path ) + list( APPEND _gtest_roots ${_native_path} ) +elseif ( GTest_HOME ) + list( APPEND _gtest_roots ${GTest_HOME} ) +endif() + +# Try the parameterized roots, if they exist +if ( _gtest_roots ) + find_path( GTEST_INCLUDE_DIR NAMES gtest/gtest.h + PATHS ${_gtest_roots} NO_DEFAULT_PATH + PATH_SUFFIXES "include" ) + find_library( GTEST_LIBRARIES NAMES gtest gtest_main + PATHS ${_gtest_roots} NO_DEFAULT_PATH + PATH_SUFFIXES "lib" ) +else () + find_path( GTEST_INCLUDE_DIR NAMES gtest/gtest.h ) + find_library( GTEST_LIBRARIES NAMES gtest ) +endif () + + +if (GTEST_INCLUDE_DIR AND GTEST_LIBRARIES) + set(GTEST_FOUND TRUE) + get_filename_component( GTEST_LIBS ${GTEST_LIBRARIES} PATH ) + set(GTEST_LIB_NAME gtest) + set(GTEST_STATIC_LIB ${GTEST_LIBS}/${CMAKE_STATIC_LIBRARY_PREFIX}${GTEST_LIB_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX}) + set(GTEST_MAIN_STATIC_LIB ${GTEST_LIBS}/${CMAKE_STATIC_LIBRARY_PREFIX}${GTEST_LIB_NAME}_main${CMAKE_STATIC_LIBRARY_SUFFIX}) + set(GTEST_SHARED_LIB ${GTEST_LIBS}/${CMAKE_SHARED_LIBRARY_PREFIX}${GTEST_LIB_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX}) +else () + set(GTEST_FOUND FALSE) +endif () + +if (GTEST_FOUND) + if (NOT GTest_FIND_QUIETLY) + message(STATUS "Found the GTest library: ${GTEST_LIBRARIES}") + endif () +else () + if (NOT GTest_FIND_QUIETLY) + set(GTEST_ERR_MSG "Could not find the GTest library. Looked in ") + if ( _gtest_roots ) + set(GTEST_ERR_MSG "${GTEST_ERR_MSG} in ${_gtest_roots}.") + else () + set(GTEST_ERR_MSG "${GTEST_ERR_MSG} system search paths.") + endif () + if (GTest_FIND_REQUIRED) + message(FATAL_ERROR "${GTEST_ERR_MSG}") + else (GTest_FIND_REQUIRED) + message(STATUS "${GTEST_ERR_MSG}") + endif (GTest_FIND_REQUIRED) + endif () +endif () + +mark_as_advanced( + GTEST_INCLUDE_DIR + GTEST_LIBS + GTEST_LIBRARIES + GTEST_STATIC_LIB + GTEST_SHARED_LIB +) diff --git a/cpp/cmake/Modules/ConfigureGoogleTest.cmake b/cpp/cmake/Modules/ConfigureGoogleTest.cmake deleted file mode 100644 index d2f2f2c666..0000000000 --- a/cpp/cmake/Modules/ConfigureGoogleTest.cmake +++ /dev/null @@ -1,59 +0,0 @@ -set(GTEST_ROOT "${CMAKE_BINARY_DIR}/googletest") - -set(GTEST_CMAKE_ARGS "") - # " -Dgtest_build_samples=ON" - # " -DCMAKE_VERBOSE_MAKEFILE=ON") - -if(NOT CMAKE_CXX11_ABI) - message(STATUS "GTEST: Disabling the GLIBCXX11 ABI") - list(APPEND GTEST_CMAKE_ARGS " -DCMAKE_C_FLAGS=-D_GLIBCXX_USE_CXX11_ABI=0") - list(APPEND GTEST_CMAKE_ARGS " -DCMAKE_CXX_FLAGS=-D_GLIBCXX_USE_CXX11_ABI=0") -elseif(CMAKE_CXX11_ABI) - message(STATUS "GTEST: Enabling the GLIBCXX11 ABI") - list(APPEND GTEST_CMAKE_ARGS " -DCMAKE_C_FLAGS=-D_GLIBCXX_USE_CXX11_ABI=1") - list(APPEND GTEST_CMAKE_ARGS " -DCMAKE_CXX_FLAGS=-D_GLIBCXX_USE_CXX11_ABI=1") -endif(NOT CMAKE_CXX11_ABI) - -configure_file("${CMAKE_SOURCE_DIR}/cmake/Templates/GoogleTest.CMakeLists.txt.cmake" - "${GTEST_ROOT}/CMakeLists.txt") - -file(MAKE_DIRECTORY "${GTEST_ROOT}/build") -file(MAKE_DIRECTORY "${GTEST_ROOT}/install") - -execute_process(COMMAND ${CMAKE_COMMAND} -G ${CMAKE_GENERATOR} . - RESULT_VARIABLE GTEST_CONFIG - WORKING_DIRECTORY ${GTEST_ROOT}) - -if(GTEST_CONFIG) - message(FATAL_ERROR "Configuring GoogleTest failed: " ${GTEST_CONFIG}) -endif(GTEST_CONFIG) - -set(PARALLEL_BUILD -j) -if($ENV{PARALLEL_LEVEL}) - set(NUM_JOBS $ENV{PARALLEL_LEVEL}) - set(PARALLEL_BUILD "${PARALLEL_BUILD}${NUM_JOBS}") -endif($ENV{PARALLEL_LEVEL}) - -if(${NUM_JOBS}) - if(${NUM_JOBS} EQUAL 1) - message(STATUS "GTEST BUILD: Enabling Sequential CMake build") - elseif(${NUM_JOBS} GREATER 1) - message(STATUS "GTEST BUILD: Enabling Parallel CMake build with ${NUM_JOBS} jobs") - endif(${NUM_JOBS} EQUAL 1) -else() - message(STATUS "GTEST BUILD: Enabling Parallel CMake build with all threads") -endif(${NUM_JOBS}) - -execute_process(COMMAND ${CMAKE_COMMAND} --build .. -- ${PARALLEL_BUILD} - RESULT_VARIABLE GTEST_BUILD - WORKING_DIRECTORY ${GTEST_ROOT}/build) - -if(GTEST_BUILD) - message(FATAL_ERROR "Building GoogleTest failed: " ${GTEST_BUILD}) -endif(GTEST_BUILD) - -message(STATUS "GoogleTest installed here: " ${GTEST_ROOT}/install) -set(GTEST_INCLUDE_DIR "${GTEST_ROOT}/install/include") -set(GTEST_LIBRARY_DIR "${GTEST_ROOT}/install/lib") -set(GTEST_FOUND TRUE) - diff --git a/cpp/cmake/Templates/GoogleTest.CMakeLists.txt.cmake b/cpp/cmake/Templates/GoogleTest.CMakeLists.txt.cmake deleted file mode 100644 index fe0035e240..0000000000 --- a/cpp/cmake/Templates/GoogleTest.CMakeLists.txt.cmake +++ /dev/null @@ -1,12 +0,0 @@ -cmake_minimum_required(VERSION 3.12) - -include(ExternalProject) - -ExternalProject_Add(GoogleTest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG release-1.8.0 - SOURCE_DIR "${GTEST_ROOT}/googletest" - BINARY_DIR "${GTEST_ROOT}/build" - INSTALL_DIR "${GTEST_ROOT}/install" - CMAKE_ARGS ${GTEST_CMAKE_ARGS} -DCMAKE_INSTALL_PREFIX=${GTEST_ROOT}/install) - diff --git a/cpp/cmake/ThirdPartyPackages.cmake b/cpp/cmake/ThirdPartyPackages.cmake new file mode 100644 index 0000000000..e85025a427 --- /dev/null +++ b/cpp/cmake/ThirdPartyPackages.cmake @@ -0,0 +1,66 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +set(GTEST_VERSION "1.8.0") + +message(MEGASEARCH_BUILD_TESTS ${MEGASEARCH_BUILD_TESTS}) + +if(MEGASEARCH_BUILD_TESTS) + add_custom_target(unittest ctest -L unittest) + + if("$ENV{GTEST_HOME}" STREQUAL "") + message("Yes") + set(GTEST_CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + + set(GTEST_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/googletest/src/googletest") + set(GTEST_INCLUDE_DIR "${GTEST_PREFIX}/include") + set(GTEST_STATIC_LIB + "${GTEST_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}") + set(GTEST_MAIN_STATIC_LIB + "${GTEST_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}gtest_main${CMAKE_STATIC_LIBRARY_SUFFIX}") + + set(GTEST_CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_INSTALL_PREFIX=${GTEST_PREFIX} + -DCMAKE_CXX_FLAGS=${GTEST_CMAKE_CXX_FLAGS}) + + ExternalProject_Add(googletest + URL "https://github.com/google/googletest/archive/release-${GTEST_VERSION}.tar.gz" + BUILD_BYPRODUCTS "${GTEST_STATIC_LIB}" "${GTEST_MAIN_STATIC_LIB}" + CMAKE_ARGS ${GTEST_CMAKE_ARGS} + ${EP_LOG_OPTIONS}) + set(GTEST_VENDORED 1) + else() + find_package(GTest REQUIRED) + set(GTEST_VENDORED 0) + endif() + + message(STATUS "GTest include dir: ${GTEST_INCLUDE_DIR}") + message(STATUS "GTest static library: ${GTEST_STATIC_LIB}") + include_directories(SYSTEM ${GTEST_INCLUDE_DIR}) + + add_library(gtest STATIC IMPORTED) + set_target_properties(gtest PROPERTIES IMPORTED_LOCATION ${GTEST_STATIC_LIB}) + + add_library(gtest_main STATIC IMPORTED) + set_target_properties(gtest_main PROPERTIES IMPORTED_LOCATION + ${GTEST_MAIN_STATIC_LIB}) + + if(GTEST_VENDORED) + add_dependencies(gtest googletest) + add_dependencies(gtest_main googletest) + endif() +endif() \ No newline at end of file diff --git a/cpp/src/license/LicenseLibrary.cpp b/cpp/src/license/LicenseLibrary.cpp index 669810552e..d67d7cdcd4 100644 --- a/cpp/src/license/LicenseLibrary.cpp +++ b/cpp/src/license/LicenseLibrary.cpp @@ -324,7 +324,7 @@ LicenseLibrary::GPUinfoFileDeserialization(const std::string &path, } ServerError -LicenseLibrary::GetDateTime(char *cha, time_t &data_time) { +LicenseLibrary::GetDateTime(const char *cha, time_t &data_time) { tm tm_; int year, month, day; sscanf(cha, "%d-%d-%d", &year, &month, &day); diff --git a/cpp/src/license/LicenseLibrary.h b/cpp/src/license/LicenseLibrary.h index a4202b1a0b..d5e97ac8a3 100644 --- a/cpp/src/license/LicenseLibrary.h +++ b/cpp/src/license/LicenseLibrary.h @@ -92,7 +92,7 @@ class LicenseLibrary { std::map &uuid_encrption_map); static ServerError - GetDateTime(char *cha, time_t &data_time); + GetDateTime(const char *cha, time_t &data_time); private: diff --git a/cpp/src/sdk/MegaSearch.cpp b/cpp/src/sdk/MegaSearch.cpp new file mode 100644 index 0000000000..66c7dceb15 --- /dev/null +++ b/cpp/src/sdk/MegaSearch.cpp @@ -0,0 +1,96 @@ +#include "MegaSearch.h" + + +namespace megasearch { +std::shared_ptr +Create() { + return nullptr; +} + +Status +Destroy(std::shared_ptr &connection_ptr) { + return Status::OK(); +} + +/** +Status +Connection::Connect(const ConnectParam ¶m) { + return Status::NotSupported("Connect interface is not supported."); +} + +Status +Connection::Connect(const std::string &uri) { + return Status::NotSupported("Connect interface is not supported."); +} + +Status +Connection::Connected() const { + return Status::NotSupported("Connected interface is not supported."); +} + +Status +Connection::Disconnect() { + return Status::NotSupported("Disconnect interface is not supported."); +} + +std::string +Connection::ClientVersion() const { + return std::string("Current Version"); +} + +Status +Connection::CreateTable(const TableSchema ¶m) { + return Status::NotSupported("Create table interface interface is not supported."); +} + +Status +Connection::CreateTablePartition(const CreateTablePartitionParam ¶m) { + return Status::NotSupported("Create table partition interface is not supported."); +} + +Status +Connection::DeleteTablePartition(const DeleteTablePartitionParam ¶m) { + return Status::NotSupported("Delete table partition interface is not supported."); +} + +Status +Connection::DeleteTable(const std::string &table_name) { + return Status::NotSupported("Create table interface is not supported."); +} + +Status +Connection::AddVector(const std::string &table_name, + const std::vector &record_array, + std::vector &id_array) { + return Status::NotSupported("Add vector array interface is not supported."); +} + +Status +Connection::SearchVector(const std::string &table_name, + const std::vector &query_record_array, + std::vector &topk_query_result_array, + int64_t topk) { + return Status::NotSupported("Query vector array interface is not supported."); +} + +Status +Connection::DescribeTable(const std::string &table_name, TableSchema &table_schema) { + return Status::NotSupported("Show table interface is not supported."); +} + +Status +Connection::ShowTables(std::vector &table_array) { + return Status::NotSupported("List table array interface is not supported."); +} + +std::string +Connection::ServerVersion() const { + return std::string("Server version."); +} + +std::string +Connection::ServerStatus() const { + return std::string("Server status"); +} +**/ +} \ No newline at end of file diff --git a/cpp/src/sdk/MegaSearch.h b/cpp/src/sdk/MegaSearch.h new file mode 100644 index 0000000000..d006927614 --- /dev/null +++ b/cpp/src/sdk/MegaSearch.h @@ -0,0 +1,339 @@ +#pragma once + +#include "Status.h" + +#include +#include +#include +#include + +/** \brief MegaSearch SDK namespace + */ +namespace megasearch { + + +/** + * @brief Column Type + */ +enum class ColumnType { + invalid, + int8, + int16, + int32, + int64, + float32, + float64, + date, + vector +}; + +/** + * @brief Index Type + */ +enum class IndexType { + raw, + ivfflat +}; + +/** + * @brief Connect API parameter + */ +struct ConnectParam { + std::string ip_address; ///< Server IP address + std::string port; ///< Server PORT +}; + +/** + * @brief Table column description + */ +struct Column { + ColumnType type = ColumnType::invalid; ///< Column Type: enum ColumnType + std::string name; ///< Column name +}; + +/** + * @brief Table vector column description + */ +struct VectorColumn : public Column { + VectorColumn() { type = ColumnType::vector; } + int64_t dimension = 0; ///< Vector dimension + IndexType index_type = IndexType::raw; ///< Index type + bool store_raw_vector = false; ///< Is vector self stored in the table +}; + +/** + * @brief Table Schema + */ +struct TableSchema { + std::string table_name; ///< Table name + std::vector vector_column_array; ///< Vector column description + std::vector attribute_column_array; ///< Columns description + std::vector partition_column_name_array; ///< Partition column name +}; + +/** + * @brief Range information + */ +struct Range { + std::string start_value; ///< Range start + std::string end_value; ///< Range stop +}; + +/** + * @brief Create table partition parameters + */ +struct CreateTablePartitionParam { + std::string table_name; ///< Table name, vector/float32/float64 type column is not allowed for partition + std::string partition_name; ///< Partition name, created partition name + std::map range_map; ///< Column name to PartitionRange map +}; + + +/** + * @brief Delete table partition parameters + */ +struct DeleteTablePartitionParam { + std::string table_name; ///< Table name + std::vector partition_name_array; ///< Partition name array +}; + +/** + * @brief Record inserted + */ +struct RowRecord { + std::map> vector_map; ///< Vector columns + std::map attribute_map; ///< Other attribute columns +}; + +/** + * @brief Query record + */ +struct QueryRecord { + std::map> vector_map; ///< Query vectors + std::vector selected_column_array; ///< Output column array + std::map> partition_filter_column_map; ///< Range used to select partitions +}; + +/** + * @brief Query result + */ +struct QueryResult { + int64_t id; ///< Output result + double score; ///< Vector similarity score: 0 ~ 100 + std::map column_map; ///< Other column +}; + +/** + * @brief TopK query result + */ +struct TopKQueryResult { + std::vector query_result_arrays; ///< TopK query result +}; + +/** + * @brief SDK main class + */ +class Connection { + public: + + /** + * @brief CreateConnection + * + * Create a connection instance and return it's shared pointer + * + * @return Connection instance pointer + */ + + static std::shared_ptr + Create(); + + /** + * @brief DestroyConnection + * + * Destroy the connection instance + * + * @param connection, the shared pointer to the instance to be destroyed + * + * @return if destroy is successful + */ + + static Status + Destroy(std::shared_ptr connection_ptr); + + /** + * @brief Connect + * + * Connect function should be called before any operations + * Server will be connected after Connect return OK + * + * @param param, use to provide server information + * + * @return Indicate if connect is successful + */ + + virtual Status Connect(const ConnectParam ¶m) = 0; + + /** + * @brief Connect + * + * Connect function should be called before any operations + * Server will be connected after Connect return OK + * + * @param uri, use to provide server information, example: megasearch://ipaddress:port + * + * @return Indicate if connect is successful + */ + virtual Status Connect(const std::string &uri) = 0; + + /** + * @brief connected + * + * Connection status. + * + * @return Indicate if connection status + */ + virtual Status Connected() const = 0; + + /** + * @brief Disconnect + * + * Server will be disconnected after Disconnect return OK + * + * @return Indicate if disconnect is successful + */ + virtual Status Disconnect() = 0; + + + /** + * @brief Create table method + * + * This method is used to create table + * + * @param param, use to provide table information to be created. + * + * @return Indicate if table is created successfully + */ + virtual Status CreateTable(const TableSchema ¶m) = 0; + + + /** + * @brief Delete table method + * + * This method is used to delete table. + * + * @param table_name, table name is going to be deleted. + * + * @return Indicate if table is delete successfully. + */ + virtual Status DeleteTable(const std::string &table_name) = 0; + + + /** + * @brief Create table partition + * + * This method is used to create table partition. + * + * @param param, use to provide partition information to be created. + * + * @return Indicate if table partition is created successfully. + */ + virtual Status CreateTablePartition(const CreateTablePartitionParam ¶m) = 0; + + + /** + * @brief Delete table partition + * + * This method is used to delete table partition. + * + * @param param, use to provide partition information to be deleted. + * + * @return Indicate if table partition is delete successfully. + */ + virtual Status DeleteTablePartition(const DeleteTablePartitionParam ¶m) = 0; + + + /** + * @brief Add vector to table + * + * This method is used to add vector array to table. + * + * @param table_name, table_name is inserted. + * @param record_array, vector array is inserted. + * @param id_array, after inserted every vector is given a id. + * + * @return Indicate if vector array are inserted successfully + */ + virtual Status AddVector(const std::string &table_name, + const std::vector &record_array, + std::vector &id_array) = 0; + + + /** + * @brief Search vector + * + * This method is used to query vector in table. + * + * @param table_name, table_name is queried. + * @param query_record_array, all vector are going to be queried. + * @param topk_query_result_array, result array. + * @param topk, how many similarity vectors will be searched. + * + * @return Indicate if query is successful. + */ + virtual Status SearchVector(const std::string &table_name, + const std::vector &query_record_array, + std::vector &topk_query_result_array, + int64_t topk) = 0; + + /** + * @brief Show table description + * + * This method is used to show table information. + * + * @param table_name, which table is show. + * @param table_schema, table_schema is given when operation is successful. + * + * @return Indicate if this operation is successful. + */ + virtual Status DescribeTable(const std::string &table_name, TableSchema &table_schema) = 0; + + /** + * @brief Show all tables in database + * + * This method is used to list all tables. + * + * @param table_array, all tables are push into the array. + * + * @return Indicate if this operation is successful. + */ + virtual Status ShowTables(std::vector &table_array) = 0; + + /** + * @brief Give the client version + * + * This method is used to give the client version. + * + * @return Client version. + */ + virtual std::string ClientVersion() const = 0; + + /** + * @brief Give the server version + * + * This method is used to give the server version. + * + * @return Server version. + */ + virtual std::string ServerVersion() const = 0; + + /** + * @brief Give the server status + * + * This method is used to give the server status. + * + * @return Server status. + */ + virtual std::string ServerStatus() const = 0; +}; + +} \ No newline at end of file diff --git a/cpp/src/sdk/Status.cpp b/cpp/src/sdk/Status.cpp new file mode 100644 index 0000000000..8e82affd2a --- /dev/null +++ b/cpp/src/sdk/Status.cpp @@ -0,0 +1,115 @@ +#include "Status.h" + + +namespace megasearch { + +Status::~Status() noexcept { + if (state_ != nullptr) { + delete state_; + state_ = nullptr; + } +} + +static inline std::ostream &operator<<(std::ostream &os, const Status &x) { + os << x.ToString(); + return os; +} + +void Status::MoveFrom(Status &s) { + delete state_; + state_ = s.state_; + s.state_ = nullptr; +} + +Status::Status(const Status &s) + : state_((s.state_ == nullptr) ? nullptr : new State(*s.state_)) {} + +Status &Status::operator=(const Status &s) { + if (state_ != s.state_) { + CopyFrom(s); + } + return *this; +} + +Status &Status::operator=(Status &&s) noexcept { + MoveFrom(s); + return *this; +} + +Status Status::operator&(const Status &status) const noexcept { + if (ok()) { + return status; + } else { + return *this; + } +} + +Status Status::operator&(Status &&s) const noexcept { + if (ok()) { + return std::move(s); + } else { + return *this; + } +} + +Status &Status::operator&=(const Status &s) noexcept { + if (ok() && !s.ok()) { + CopyFrom(s); + } + return *this; +} + +Status &Status::operator&=(Status &&s) noexcept { + if (ok() && !s.ok()) { + MoveFrom(s); + } + return *this; +} + +Status::Status(StatusCode code, const std::string &message) { + state_ = new State; + state_->code = code; + state_->message = message; +} + +void Status::CopyFrom(const Status &status) { + delete state_; + if (status.state_ == nullptr) { + state_ = nullptr; + } else { + state_ = new State(*status.state_); + } +} + +std::string Status::CodeAsString() const { + if (state_ == nullptr) { + return "OK"; + } + + const char *type = nullptr; + switch (code()) { + case StatusCode::OK: type = "OK"; + break; + case StatusCode::Invalid: type = "Invalid"; + break; + case StatusCode::UnknownError: type = "Unknown error"; + break; + case StatusCode::NotSupported: type = "Not Supported"; + break; + default: type = "Unknown"; + break; + } + return std::string(type); +} + +std::string Status::ToString() const { + std::string result(CodeAsString()); + if (state_ == nullptr) { + return result; + } + result += ": "; + result += state_->message; + return result; +} + +} \ No newline at end of file diff --git a/cpp/src/sdk/Status.h b/cpp/src/sdk/Status.h new file mode 100644 index 0000000000..25f9ac8c1d --- /dev/null +++ b/cpp/src/sdk/Status.h @@ -0,0 +1,325 @@ +#pragma once + +#include +#include + +/** \brief MegaSearch SDK namespace + */ +namespace megasearch { + +/** + * @brief Status Code for SDK interface return + */ +enum class StatusCode { + OK = 0, + Invalid = 1, + UnknownError = 2, + NotSupported = 3 +}; + +/** + * @brief Status for SDK interface return + */ +class Status { + public: + /** + * @brief Status + * + * Default constructor. + * + */ + Status() = default; + + /** + * @brief Status + * + * Destructor. + * + */ + ~Status() noexcept; + + /** + * @brief Status + * + * Constructor + * + * @param code, status code. + * @param message, status message. + * + */ + Status(StatusCode code, const std::string &message); + + /** + * @brief Status + * + * Copy constructor + * + * @param status, status to be copied. + * + */ + inline Status(const Status &status); + + /** + * @brief Status + * + * Assignment operator + * + * @param status, status to be copied. + * @return, the status is assigned. + * + */ + inline Status &operator=(const Status &s); + + /** + * @brief Status + * + * Move constructor + * + * @param status, status to be moved. + * + */ + inline Status(Status &&s) noexcept : state_(s.state_) {}; + + /** + * @brief Status + * + * Move assignment operator + * + * @param status, status to be moved. + * @return, the status is moved. + * + */ + inline Status &operator=(Status &&s) noexcept; + + /** + * @brief Status + * + * AND operator + * + * @param status, status to be AND. + * @return, the status after AND operation. + * + */ + inline Status operator&(const Status &s) const noexcept; + + /** + * @brief Status + * + * AND operator + * + * @param status, status to be AND. + * @return, the status after AND operation. + * + */ + inline Status operator&(Status &&s) const noexcept; + + /** + * @brief Status + * + * AND operator + * + * @param status, status to be AND. + * @return, the status after AND operation. + * + */ + inline Status &operator&=(const Status &s) noexcept; + + /** + * @brief Status + * + * AND operator + * + * @param status, status to be AND. + * @return, the status after AND operation. + * + */ + inline Status &operator&=(Status &&s) noexcept; + + /** + * @brief OK + * + * static OK status constructor + * + * @return, the status with OK. + * + */ + static Status OK() { return Status(); } + + /** + * @brief OK + * + * static OK status constructor with a specific message + * + * @param, serveral specific messages + * @return, the status with OK. + * + */ + template + static Status OK(Args &&... args) { + return Status(StatusCode::OK, MessageBuilder(std::forward(args)...)); + } + + /** + * @brief Invalid + * + * static Invalid status constructor with a specific message + * + * @param, serveral specific messages + * @return, the status with Invalid. + * + */ + template + static Status Invalid(Args &&... args) { + return Status(StatusCode::Invalid, + MessageBuilder(std::forward(args)...)); + } + + /** + * @brief Unknown Error + * + * static unknown error status constructor with a specific message + * + * @param, serveral specific messages + * @return, the status with unknown error. + * + */ + template + static Status UnknownError(Args &&... args) { + return Status(StatusCode::UnknownError, MessageBuilder(std::forward(args)...)); + } + + /** + * @brief not supported Error + * + * static not supported status constructor with a specific message + * + * @param, serveral specific messages + * @return, the status with not supported error. + * + */ + template + static Status NotSupported(Args &&... args) { + return Status(StatusCode::NotSupported, MessageBuilder(std::forward(args)...)); + } + + /** + * @brief ok + * + * Return true iff the status indicates success. + * + * @return, if the status indicates success. + * + */ + bool ok() const { return (state_ == nullptr); } + + /** + * @brief IsInvalid + * + * Return true iff the status indicates invalid. + * + * @return, if the status indicates invalid. + * + */ + bool IsInvalid() const { return code() == StatusCode::Invalid; } + + /** + * @brief IsUnknownError + * + * Return true iff the status indicates unknown error. + * + * @return, if the status indicates unknown error. + * + */ + bool IsUnknownError() const { return code() == StatusCode::UnknownError; } + + /** + * @brief IsNotSupported + * + * Return true iff the status indicates not supported. + * + * @return, if the status indicates not supported. + * + */ + bool IsNotSupported() const { return code() == StatusCode::NotSupported; } + + /** + * @brief ToString + * + * Return error message string. + * + * @return, error message string. + * + */ + std::string ToString() const; + + /** + * @brief CodeAsString + * + * Return a string representation of the status code. + * + * @return, a string representation of the status code. + * + */ + std::string CodeAsString() const; + + /** + * @brief code + * + * Return the StatusCode value attached to this status. + * + * @return, the status code value attached to this status. + * + */ + StatusCode code() const { return ok() ? StatusCode::OK : state_->code; } + + /** + * @brief message + * + * Return the specific error message attached to this status. + * + * @return, the specific error message attached to this status. + * + */ + std::string message() const { return ok() ? "" : state_->message; } + + private: + struct State { + StatusCode code; + std::string message; + }; + + // OK status has a `nullptr` state_. Otherwise, `state_` points to + // a `State` structure containing the error code and message. + State *state_ = nullptr; + + void DeleteState() { + delete state_; + state_ = nullptr; + } + + void CopyFrom(const Status &s); + + inline void MoveFrom(Status &s); + + template + static void MessageBuilderRecursive(std::stringstream &stream, Head &&head) { + stream << head; + } + + template + static void MessageBuilderRecursive(std::stringstream &stream, Head &&head, Tail &&... tail) { + MessageBuilderRecursive(stream, std::forward(head)); + MessageBuilderRecursive(stream, std::forward(tail)...); + } + + template + static std::string MessageBuilder(Args &&... args) { + std::stringstream stream; + + MessageBuilderRecursive(stream, std::forward(args)...); + + return stream.str(); + } +}; + +} \ No newline at end of file diff --git a/cpp/unittest/license/license_library_tests.cpp b/cpp/unittest/license/license_library_tests.cpp index f47ce5a43f..c68f243d4e 100644 --- a/cpp/unittest/license/license_library_tests.cpp +++ b/cpp/unittest/license/license_library_tests.cpp @@ -128,8 +128,8 @@ TEST(LicenseLibraryTest, LICENSE_FILE_TEST) { // 11.GetDateTime time_t starting_time; time_t end_time; - char *string_starting_time = "2019-05-10"; - char *string_end_time = "2022-05-10"; + const char *string_starting_time = "2019-05-10"; + const char *string_end_time = "2022-05-10"; err = server::LicenseLibrary::GetDateTime(string_starting_time, starting_time); ASSERT_EQ(err, server::SERVER_SUCCESS); err = server::LicenseLibrary::GetDateTime(string_end_time, end_time); diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/python/.gitignore b/python/.gitignore new file mode 100644 index 0000000000..e69de29bb2