diff --git a/Admin/ApplicationAdminServer.cpp b/Admin/ApplicationAdminServer.cpp index 7a5f648df5..066392d201 100644 --- a/Admin/ApplicationAdminServer.cpp +++ b/Admin/ApplicationAdminServer.cpp @@ -36,6 +36,7 @@ #include "Basics/ProgramOptionsDescription.h" #include "HttpServer/HttpHandlerFactory.h" #include "HttpServer/PathHandler.h" +#include "Logger/Logger.h" #include "Rest/HttpResponse.h" using namespace std; @@ -43,25 +44,6 @@ using namespace triagens::basics; using namespace triagens::rest; using namespace triagens::admin; -// ----------------------------------------------------------------------------- -// --SECTION-- static private variables -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup RestServer -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief option for the directory containing the admin files -//////////////////////////////////////////////////////////////////////////////// - -string ApplicationAdminServer::optionAdminDirectory; - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- static public methods // ----------------------------------------------------------------------------- @@ -100,8 +82,17 @@ ApplicationAdminServer::ApplicationAdminServer () : _allowLogViewer(false), _allowAdminDirectory(false), _allowFeConfiguration(false), - _allowVersion(false) { + _allowVersion(false), + _adminDirectory(), + _pathOptions(0), + _feConfiguration(), + _name(), + _version() { _pathOptions = new PathHandler::Options(); + +#ifdef _PKGDATADIR_ + _adminDirectory = string(_PKGDATADIR_) + "/html/admin"; +#endif } //////////////////////////////////////////////////////////////////////////////// @@ -202,8 +193,10 @@ void ApplicationAdminServer::addHandlers (HttpHandlerFactory* factory, string co // ............................................................................. if (_allowAdminDirectory) { - if (! optionAdminDirectory.empty()) { - reinterpret_cast(_pathOptions)->path = optionAdminDirectory; + if (! _adminDirectory.empty()) { + LOGGER_INFO << "using JavaScript front-end files stored at '" << _adminDirectory << "'"; + + reinterpret_cast(_pathOptions)->path = _adminDirectory; reinterpret_cast(_pathOptions)->contentType = "text/plain"; reinterpret_cast(_pathOptions)->allowSymbolicLink = false; reinterpret_cast(_pathOptions)->defaultFile = "index.html"; @@ -237,7 +230,7 @@ void ApplicationAdminServer::addHandlers (HttpHandlerFactory* factory, string co void ApplicationAdminServer::setupOptions (map& options) { if (_allowAdminDirectory) { options[ApplicationServer::OPTIONS_SERVER + ":help-admin"] - ("server.admin-directory", &optionAdminDirectory, "directory containing the ADMIN front-end") + ("server.admin-directory", &_adminDirectory, "directory containing the ADMIN front-end") ; } diff --git a/Admin/ApplicationAdminServer.h b/Admin/ApplicationAdminServer.h index ae3635590d..99b6247c73 100644 --- a/Admin/ApplicationAdminServer.h +++ b/Admin/ApplicationAdminServer.h @@ -195,27 +195,6 @@ namespace triagens { /// @} //////////////////////////////////////////////////////////////////////////////// -// ----------------------------------------------------------------------------- -// --SECTION-- static private variables -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup RestServer -/// @{ -//////////////////////////////////////////////////////////////////////////////// - - private: - -//////////////////////////////////////////////////////////////////////////////// -/// @brief option for the directory containing the admin files -//////////////////////////////////////////////////////////////////////////////// - - static string optionAdminDirectory; - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- private variables // ----------------------------------------------------------------------------- diff --git a/ApplicationServer/ApplicationServerImpl.cpp b/ApplicationServer/ApplicationServerImpl.cpp index dbf69a531e..5b384777d2 100644 --- a/ApplicationServer/ApplicationServerImpl.cpp +++ b/ApplicationServer/ApplicationServerImpl.cpp @@ -344,7 +344,7 @@ namespace triagens { seteuid(_loggingUid); #endif - TRI_CloseLogging(); + bool threaded = TRI_ShutdownLogging(); Logger::setApplicationName(logApplicationName); Logger::setHostName(logHostName); @@ -368,6 +368,8 @@ namespace triagens { TRI_SetPrefixLogging(logPrefix); TRI_SetThreadIdentifierLogging(logThreadId); + TRI_InitialiseLogging(threaded); + TRI_CreateLogAppenderFile(logFile); TRI_CreateLogAppenderSyslog(logPrefix, logSyslog); @@ -392,10 +394,11 @@ namespace triagens { // do not use init files if (StringUtils::tolower(initFile) == string("none")) { + LOGGER_INFO << "using no init file at all"; return true; } - LOGGER_DEBUG << "using init file '" << initFile << "'"; + LOGGER_INFO << "using init file '" << initFile << "'"; bool ok = options.parse(descriptionFile, initFile); @@ -407,6 +410,9 @@ namespace triagens { return ok; } + else { + LOGGER_DEBUG << "no init file has been specified"; + } // nothing has been specified on the command line regarding configuration file if (! userConfigFile.empty()) { @@ -424,7 +430,7 @@ namespace triagens { // check and see if file exists if (FileUtils::exists(homeDir)) { - LOGGER_DEBUG << "using init file '" << homeDir << "'"; + LOGGER_INFO << "using user init file '" << homeDir << "'"; bool ok = options.parse(descriptionFile, homeDir); @@ -436,14 +442,21 @@ namespace triagens { return ok; } + else { + LOGGER_INFO << "no user init file '" << homeDir << "' found"; + } + } + else { + LOGGER_DEBUG << "no user init file, $HOME is empty"; } } #ifdef _SYSCONFDIR_ // try the configuration file in the system directory - if there is one - // note that the system directory is dependent upon how the user installed - // the application server. + + // Please note that the system directory changes depending on + // where the user installed the application server. if (! systemConfigFile.empty()) { string sysDir = string(_SYSCONFDIR_); @@ -458,7 +471,7 @@ namespace triagens { // check and see if file exists if (FileUtils::exists(sysDir)) { - LOGGER_DEBUG << "using init file '" << sysDir << "'"; + LOGGER_INFO << "using init file '" << sysDir << "'"; bool ok = options.parse(descriptionFile, sysDir); @@ -470,6 +483,12 @@ namespace triagens { return ok; } + else { + LOGGER_INFO << "no system init file '" << sysDir << "' found"; + } + } + else { + LOGGER_DEBUG << "no system init file, not system directory is known"; } } diff --git a/BasicsC/logging.c b/BasicsC/logging.c index 9f7d4b53e4..29cd2bd9ec 100644 --- a/BasicsC/logging.c +++ b/BasicsC/logging.c @@ -548,6 +548,7 @@ static void OutputMessage (TRI_log_level_e level, msg._message = copy ? TRI_DuplicateString2(message, length) : message; msg._length = length; + // this will COPY the structure log_message_t into the vector TRI_LockMutex(&LogMessageQueueLock); TRI_PushBackVector(&LogMessageQueue, (void*) &msg); TRI_UnlockMutex(&LogMessageQueueLock); @@ -1664,7 +1665,7 @@ void TRI_InitialiseLogging (bool threaded) { // always close logging at the end if (! ShutdownInitalised) { - atexit(TRI_ShutdownLogging); + atexit((void (*)(void)) TRI_ShutdownLogging); ShutdownInitalised = true; } } @@ -1714,9 +1715,9 @@ void TRI_ReopenLogging () { /// @brief shut downs the logging components //////////////////////////////////////////////////////////////////////////////// -void TRI_ShutdownLogging () { +bool TRI_ShutdownLogging () { if (! Initialised) { - return; + return ThreadedLogging; } // logging is now inactive @@ -1749,6 +1750,8 @@ void TRI_ShutdownLogging () { TRI_DestroyMutex(&BufferLock); Initialised = false; + + return ThreadedLogging; } //////////////////////////////////////////////////////////////////////////////// diff --git a/BasicsC/logging.h b/BasicsC/logging.h index 244c4e4b5f..d06afe2f0c 100644 --- a/BasicsC/logging.h +++ b/BasicsC/logging.h @@ -502,7 +502,7 @@ void TRI_ReopenLogging (void); /// @brief shut downs the logging components //////////////////////////////////////////////////////////////////////////////// -void TRI_ShutdownLogging (void); +bool TRI_ShutdownLogging (void); //////////////////////////////////////////////////////////////////////////////// /// @} diff --git a/Doxygen/Examples.AvocadoDB/startup1 b/Doxygen/Examples.AvocadoDB/startup1 new file mode 100644 index 0000000000..4e59e787ad --- /dev/null +++ b/Doxygen/Examples.AvocadoDB/startup1 @@ -0,0 +1,5 @@ +> ./avocado --server.http-port 12345 /tmp/vocbase +2012-02-05T13:23:52Z [455] INFO AvocadoDB (version 0.0.8 [exported]) is ready for business +2012-02-05T13:23:52Z [455] INFO HTTP client port: 12345 +2012-02-05T13:23:52Z [455] INFO HTTP admin port: localhost:8530 +2012-02-05T13:23:52Z [455] INFO Have Fun! diff --git a/GeneralServer/GeneralListenTask.h b/GeneralServer/GeneralListenTask.h index 3e940afcc5..b754ebfbd0 100644 --- a/GeneralServer/GeneralListenTask.h +++ b/GeneralServer/GeneralListenTask.h @@ -44,7 +44,7 @@ namespace triagens { GeneralListenTask& operator= (GeneralListenTask const&); public: - +/* //////////////////////////////////////////////////////////////////////////////// /// @brief listen to given address and port //////////////////////////////////////////////////////////////////////////////// @@ -60,6 +60,14 @@ namespace triagens { GeneralListenTask (S* server, int port, bool reuseAddress) : Task("GeneralListenTask"), ListenTask(port, reuseAddress), server(server) { } +*/ + //////////////////////////////////////////////////////////////////////////////// + /// @brief listen to given port + //////////////////////////////////////////////////////////////////////////////// + + GeneralListenTask (S* server, struct addrinfo *aip, bool reuseAddress) + : Task("GeneralListenTask"), ListenTask(aip, reuseAddress), server(server) { + } protected: diff --git a/GeneralServer/GeneralServer.h b/GeneralServer/GeneralServer.h index 7f4539ea0c..a3e133e956 100644 --- a/GeneralServer/GeneralServer.h +++ b/GeneralServer/GeneralServer.h @@ -31,6 +31,14 @@ #include +#include +#include +#include + +#include +#include +#include + #include #include #include @@ -193,16 +201,61 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// bool addPort (string const& address, int port, bool reuseAddress) { - ListenTask* task = new GeneralListenTask(dynamic_cast(this), address, port, reuseAddress); + struct addrinfo *result, *aip; + struct addrinfo hints; + int error; - if (! task->isBound()) { - deleteTask(task); - return false; + memset(&hints, 0, sizeof (struct addrinfo)); + hints.ai_family = AF_UNSPEC; // Allow IPv4 or IPv6 + hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + + string portString = basics::StringUtils::itoa(port); + + if (address.empty()) { + error = getaddrinfo(NULL, portString.c_str(), &hints, &result); + } + else { + error = getaddrinfo(address.c_str(), portString.c_str(), &hints, &result); } - _scheduler->registerTask(task); + if (error != 0) { + LOGGER_ERROR << "getaddrinfo for host: " << address.c_str() << " => " << gai_strerror(error); + return false; + } + + bool gotTask = false; + + // Try all returned addresses + for (aip = result; aip != NULL; aip = aip->ai_next) { + + ListenTask* task = new GeneralListenTask (dynamic_cast (this), aip, reuseAddress); - return true; + if (! task->isBound()) { + deleteTask(task); + } + else { + _scheduler->registerTask(task); + gotTask = true; + } + + } + + freeaddrinfo(result); + + return gotTask; + +// ListenTask* task = new GeneralListenTask (dynamic_cast (this), address, port, reuseAddress); +// +// if (! task->isBound()) { +// deleteTask(task); +// return false; +// } +// +// _scheduler->registerTask(task); +// +// return true; } public: diff --git a/Makefile.am b/Makefile.am index 68d226b015..5225d348de 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,8 @@ ACLOCAL_AMFLAGS = -I m4 AM_CFLAGS = -AM_CPPFLAGS = +AM_CXXFLAGS = +AM_CPPFLAGS = -D_SYSCONFDIR_='"${sysconfdir}"' -D_PKGDATADIR_='"${pkgdatadir}"' AM_LDFLAGS = BUILT_SOURCES = .setup-directories LIBS = @@ -9,6 +10,15 @@ LIBS = noinst_LIBRARIES = libavocadodb.a bin_PROGRAMS = avocado +nobase_pkgdata_DATA = \ + $(shell find @srcdir@/js/system -name "*.js" -print) \ + $(shell find @srcdir@/html -name "*.css" -print) \ + $(shell find @srcdir@/html -name "*.gif" -print) \ + $(shell find @srcdir@/html -name "*.html" -print) \ + $(shell find @srcdir@/html -name "*.ico" -print) \ + $(shell find @srcdir@/html -name "*.js" -print) \ + $(shell find @srcdir@/html -name "*.png" -print) + ################################################################################ ## avocado ################################################################################ @@ -89,6 +99,9 @@ Doxygen/js/system/%.c: @srcdir@/js/system/%.js .setup-directories Doxygen/js/modules/%.c: @srcdir@/js/system/%.js .setup-directories python @top_srcdir@/Doxygen/Scripts/js2doxy.py $< > $@ +Doxygen/js/bootstrap/%.c: @srcdir@/js/bootstrap/%.js .setup-directories + python @top_srcdir@/Doxygen/Scripts/js2doxy.py $< > $@ + doxygen: Doxygen/avocado.doxy $(DOXYGEN) doxygen Doxygen/avocado.doxy diff --git a/Makefile.files b/Makefile.files index 49b99e340f..ddd83881bb 100644 --- a/Makefile.files +++ b/Makefile.files @@ -3,6 +3,7 @@ ################################################################################ libavocadodb_a_CPPFLAGS = \ + $(AM_CPPFLAGS) \ @BOOST_CPPFLAGS@ \ @LIBEV_CPPFLAGS@ \ @MATH_CPPFLAGS@ \ @@ -158,6 +159,8 @@ libavocadodb_a_SOURCES = \ VocBase/datafile.c \ VocBase/document-collection.c \ VocBase/fluent-query.c \ + VocBase/select-result.c \ + VocBase/join.c \ VocBase/query.c \ VocBase/headers.c \ VocBase/index.c \ @@ -178,6 +181,7 @@ libavocadodb_a_SOURCES = \ QL/tokens.c avocado_CPPFLAGS = \ + $(AM_CPPFLAGS) \ @BOOST_CPPFLAGS@ \ @LIBEV_CPPFLAGS@ \ @MATH_CPPFLAGS@ \ @@ -311,6 +315,9 @@ WIKI = \ Doxygen/xml/da/db6/InstallManual.md \ Doxygen/xml/dd/dd7/RefManual.md +Doxygen/xml/da/db6/InstallManual.md: Doxygen/xml/da/db6/InstallManual.xml + python @top_srcdir@/Doxygen/Scripts/xml2md.py $< > $@ + Doxygen/xml/dd/dd7/RefManual.md: Doxygen/xml/dd/dd7/RefManual.xml python @top_srcdir@/Doxygen/Scripts/xml2md.py $< > $@ diff --git a/QL/ParserWrapper.cpp b/QL/ParserWrapper.cpp index 4f488ce842..6b1b778f5c 100644 --- a/QL/ParserWrapper.cpp +++ b/QL/ParserWrapper.cpp @@ -49,7 +49,6 @@ ParseError::ParseError (const string& message, const size_t line, const size_t c _message(message), _line(line), _column(column) { } - //////////////////////////////////////////////////////////////////////////////// /// @brief Destroy the instance //////////////////////////////////////////////////////////////////////////////// @@ -68,7 +67,6 @@ string ParseError::getDescription () const { return errorMessage.str(); } - // ----------------------------------------------------------------------------- // --SECTION-- class ParserWrapper // ----------------------------------------------------------------------------- @@ -95,7 +93,6 @@ ParserWrapper::~ParserWrapper () { } } - //////////////////////////////////////////////////////////////////////////////// /// @brief Parse the query passed //////////////////////////////////////////////////////////////////////////////// @@ -141,16 +138,14 @@ bool ParserWrapper::parse () { return true; } - //////////////////////////////////////////////////////////////////////////////// /// @brief Get a parse error that may have occurred //////////////////////////////////////////////////////////////////////////////// -ParseError *ParserWrapper::getParseError () { +ParseError* ParserWrapper::getParseError () { return _parseError; } - //////////////////////////////////////////////////////////////////////////////// /// @brief Get the type of the query //////////////////////////////////////////////////////////////////////////////// @@ -163,44 +158,44 @@ QL_ast_query_type_e ParserWrapper::getQueryType () { return _context->_query->_type; } - //////////////////////////////////////////////////////////////////////////////// /// @brief Create a select clause //////////////////////////////////////////////////////////////////////////////// -TRI_qry_select_t *ParserWrapper::getSelect () { +TRI_qry_select_t* ParserWrapper::getSelect () { TRI_qry_select_t* select = 0; - if (_isParsed) { - QLOptimizeExpression(_context->_query->_select._base); - QL_ast_query_select_type_e selectType = QLOptimizeGetSelectType(_context->_query); + if (!_isParsed) { + return 0; + } - if (selectType == QLQuerySelectTypeSimple) { - select = TRI_CreateQuerySelectDocument(); - } - else if (selectType == QLQuerySelectTypeEvaluated) { - QL_javascript_conversion_t *selectJs = QLJavascripterInit(); - if (selectJs != 0) { - TRI_AppendStringStringBuffer(selectJs->_buffer, "(function($) { return "); - QLJavascripterConvert(selectJs, _context->_query->_select._base); - TRI_AppendStringStringBuffer(selectJs->_buffer, " })"); - select = TRI_CreateQuerySelectGeneral(selectJs->_buffer->_buffer); - // TODO: REMOVE ME - // std::cout << "SELECT: " << selectJs->_buffer->_buffer << "\n"; - QLJavascripterFree(selectJs); - } + QLOptimizeExpression(_context->_query->_select._base); + QL_ast_query_select_type_e selectType = QLOptimizeGetSelectType(_context->_query); + + if (selectType == QLQuerySelectTypeSimple) { + select = TRI_CreateQuerySelectDocument(); + } + else if (selectType == QLQuerySelectTypeEvaluated) { + QL_javascript_conversion_t *selectJs = QLJavascripterInit(); + if (selectJs != 0) { + TRI_AppendStringStringBuffer(selectJs->_buffer, "(function($) { return "); + QLJavascripterConvert(selectJs, _context->_query->_select._base); + TRI_AppendStringStringBuffer(selectJs->_buffer, " })"); + select = TRI_CreateQuerySelectGeneral(selectJs->_buffer->_buffer); + // TODO: REMOVE ME + // std::cout << "SELECT: " << selectJs->_buffer->_buffer << "\n"; + QLJavascripterFree(selectJs); } } return select; } - //////////////////////////////////////////////////////////////////////////////// /// @brief Get the alias of the primary collection //////////////////////////////////////////////////////////////////////////////// -char *ParserWrapper::getPrimaryAlias () { +char* ParserWrapper::getPrimaryAlias () { if (_isParsed) { return QLAstQueryGetPrimaryAlias(_context->_query); } @@ -208,12 +203,11 @@ char *ParserWrapper::getPrimaryAlias () { return 0; } - //////////////////////////////////////////////////////////////////////////////// /// @brief Get the name of the primary collection //////////////////////////////////////////////////////////////////////////////// -char *ParserWrapper::getPrimaryName () { +char* ParserWrapper::getPrimaryName () { if (_isParsed) { return QLAstQueryGetPrimaryName(_context->_query); } @@ -221,97 +215,175 @@ char *ParserWrapper::getPrimaryName () { return 0; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief Create joins +//////////////////////////////////////////////////////////////////////////////// + +TRI_select_join_t* ParserWrapper::getJoins () { + TRI_select_join_t* join = 0; + char *collectionName; + char *collectionAlias; + + if (!_isParsed ) { + return NULL; + } + + join = TRI_CreateSelectJoin(); + if (!join) { + return NULL; + } + + QL_ast_node_t *node = (QL_ast_node_t *) _context->_query->_from._base; + node = (QL_ast_node_t *) node->_next; + + assert(node != 0); + + // primary table + QL_ast_node_t *lhs = (QL_ast_node_t *) node->_lhs; + QL_ast_node_t *rhs = (QL_ast_node_t *) node->_rhs; + collectionName = lhs->_value._stringValue; + collectionAlias = rhs->_value._stringValue; + + TRI_AddPartSelectJoin(join, JOIN_TYPE_PRIMARY, NULL, collectionName, collectionAlias); + + while (node->_next) { + node = (QL_ast_node_t *) node->_next; + QL_ast_node_t *ref = (QL_ast_node_t *) node->_lhs; + QL_ast_node_t *condition = (QL_ast_node_t *) node->_rhs; + + QLOptimizeExpression(condition); + QL_ast_query_where_type_e conditionType = QLOptimizeGetWhereType(condition); + + TRI_qry_where_t* joinWhere = 0; + + if (conditionType == QLQueryWhereTypeAlwaysTrue) { + // join condition is always true + joinWhere = TRI_CreateQueryWhereBoolean(true); + } + else if (conditionType == QLQueryWhereTypeAlwaysFalse) { + // join condition is always false + joinWhere = TRI_CreateQueryWhereBoolean(false); + } + else { + // where condition must be evaluated for each result + QL_javascript_conversion_t *conditionJs = QLJavascripterInit(); + if (conditionJs != 0) { + TRI_AppendStringStringBuffer(conditionJs->_buffer, "(function($) { return ("); + QLJavascripterConvert(conditionJs, condition); + TRI_AppendStringStringBuffer(conditionJs->_buffer, "); })"); + joinWhere = TRI_CreateQueryWhereGeneral(conditionJs->_buffer->_buffer); + QLJavascripterFree(conditionJs); + } + } + + collectionName = ((QL_ast_node_t *) (ref->_lhs))->_value._stringValue; + collectionAlias = ((QL_ast_node_t *) (ref->_rhs))->_value._stringValue; + + if (node->_type == QLNodeJoinList) { + TRI_AddPartSelectJoin(join, JOIN_TYPE_LIST, joinWhere, collectionName, collectionAlias); + } + else if (node->_type == QLNodeJoinInner) { + TRI_AddPartSelectJoin(join, JOIN_TYPE_INNER, joinWhere, collectionName, collectionAlias); + } + else if (node->_type == QLNodeJoinLeft || node->_type == QLNodeJoinRight) { + TRI_AddPartSelectJoin(join, JOIN_TYPE_OUTER, joinWhere, collectionName, collectionAlias); + } + } + + return join; +} //////////////////////////////////////////////////////////////////////////////// /// @brief Create a where clause //////////////////////////////////////////////////////////////////////////////// -TRI_qry_where_t *ParserWrapper::getWhere () { +TRI_qry_where_t* ParserWrapper::getWhere () { TRI_qry_where_t* where = 0; - if (_isParsed) { - QLOptimizeExpression(_context->_query->_where._base); - // TODO: REMOVE ME - // QL_formatter_t f; - // f.indentLevel = 0; - // QLFormatterDump(_context->_query->_where._base, &f, 0); + if (!_isParsed) { + return NULL; + } - _context->_query->_where._type = QLOptimizeGetWhereType(_context->_query); + QLOptimizeExpression(_context->_query->_where._base); + // TODO: REMOVE ME + // QL_formatter_t f; + // f.indentLevel = 0; + // QLFormatterDump(_context->_query->_where._base, &f, 0); - if (_context->_query->_where._type == QLQueryWhereTypeAlwaysTrue) { - // where condition is always true - where = TRI_CreateQueryWhereBoolean(true); - } - else if (_context->_query->_where._type == QLQueryWhereTypeAlwaysFalse) { - // where condition is always false - where = TRI_CreateQueryWhereBoolean(false); - } - else { - // where condition must be evaluated for each result - QL_javascript_conversion_t *whereJs = QLJavascripterInit(); - if (whereJs != 0) { - TRI_AppendStringStringBuffer(whereJs->_buffer, "(function($) { return ("); - QLJavascripterConvert(whereJs, _context->_query->_where._base); - TRI_AppendStringStringBuffer(whereJs->_buffer, "); })"); - where = TRI_CreateQueryWhereGeneral(whereJs->_buffer->_buffer); - // TODO: REMOVE ME - // std::cout << "WHERE: " << whereJs->_buffer->_buffer << "\n"; - QLJavascripterFree(whereJs); - } + _context->_query->_where._type = QLOptimizeGetWhereType(_context->_query->_where._base); + + if (_context->_query->_where._type == QLQueryWhereTypeAlwaysTrue) { + // where condition is always true + where = TRI_CreateQueryWhereBoolean(true); + } + else if (_context->_query->_where._type == QLQueryWhereTypeAlwaysFalse) { + // where condition is always false + where = TRI_CreateQueryWhereBoolean(false); + } + else { + // where condition must be evaluated for each result + QL_javascript_conversion_t *whereJs = QLJavascripterInit(); + if (whereJs != 0) { + TRI_AppendStringStringBuffer(whereJs->_buffer, "(function($) { return ("); + QLJavascripterConvert(whereJs, _context->_query->_where._base); + TRI_AppendStringStringBuffer(whereJs->_buffer, "); })"); + where = TRI_CreateQueryWhereGeneral(whereJs->_buffer->_buffer); + // TODO: REMOVE ME + // std::cout << "WHERE: " << whereJs->_buffer->_buffer << "\n"; + QLJavascripterFree(whereJs); } } return where; } - //////////////////////////////////////////////////////////////////////////////// /// @brief Create an order clause //////////////////////////////////////////////////////////////////////////////// -TRI_qry_order_t *ParserWrapper::getOrder () { +TRI_qry_order_t* ParserWrapper::getOrder () { TRI_qry_order_t* order = 0; - if (_isParsed ) { - if (_context->_query->_order._base) { - QLOptimizeOrder(_context->_query->_order._base); - QL_javascript_conversion_t *orderJs = QLJavascripterInit(); - if (orderJs != 0) { - TRI_AppendStringStringBuffer(orderJs->_buffer, "(function($) { return ("); - QLJavascripterConvertOrder(orderJs, (QL_ast_node_t *) _context->_query->_order._base->_next); - TRI_AppendStringStringBuffer(orderJs->_buffer, "); })"); - order = TRI_CreateQueryOrderGeneral(orderJs->_buffer->_buffer); - // TODO: REMOVE ME - std::cout << "ORDER: " << orderJs->_buffer->_buffer << "\n"; - QLJavascripterFree(orderJs); - } + if (!_isParsed ) { + return NULL; + } + + if (_context->_query->_order._base) { + QLOptimizeOrder(_context->_query->_order._base); + QL_javascript_conversion_t *orderJs = QLJavascripterInit(); + if (orderJs != 0) { + TRI_AppendStringStringBuffer(orderJs->_buffer, "(function($) { return ("); + QLJavascripterConvertOrder(orderJs, (QL_ast_node_t *) _context->_query->_order._base->_next); + TRI_AppendStringStringBuffer(orderJs->_buffer, "); })"); + order = TRI_CreateQueryOrderGeneral(orderJs->_buffer->_buffer); + // TODO: REMOVE ME + // std::cout << "ORDER: " << orderJs->_buffer->_buffer << "\n"; + QLJavascripterFree(orderJs); } } return order; } - //////////////////////////////////////////////////////////////////////////////// /// @brief Get the skip value //////////////////////////////////////////////////////////////////////////////// TRI_voc_size_t ParserWrapper::getSkip () { - TRI_voc_size_t skip = 0; + TRI_voc_size_t skip = 0; if (_isParsed) { if (_context->_query->_limit._isUsed) { skip = (TRI_voc_size_t) _context->_query->_limit._offset; } else { - skip = TRI_QRY_NO_SKIP; + skip = TRI_QRY_NO_SKIP; } } return skip; } - //////////////////////////////////////////////////////////////////////////////// /// @brief Get the limit value //////////////////////////////////////////////////////////////////////////////// diff --git a/QL/ParserWrapper.h b/QL/ParserWrapper.h index b16b4f3596..43e94edcc5 100644 --- a/QL/ParserWrapper.h +++ b/QL/ParserWrapper.h @@ -42,6 +42,7 @@ #include "QL/javascripter.h" #include "VocBase/query.h" +#include "VocBase/join.h" using namespace std; @@ -70,14 +71,12 @@ namespace triagens { ParseError(const string&, const size_t, const size_t); - //////////////////////////////////////////////////////////////////////////////// /// @brief Destroy the instance //////////////////////////////////////////////////////////////////////////////// ~ParseError(); - //////////////////////////////////////////////////////////////////////////////// /// @brief Get the parse error as a formatted string //////////////////////////////////////////////////////////////////////////////// @@ -92,14 +91,12 @@ namespace triagens { string _message; - //////////////////////////////////////////////////////////////////////////////// /// @brief Line in which the error occurred //////////////////////////////////////////////////////////////////////////////// size_t _line; - //////////////////////////////////////////////////////////////////////////////// /// @brief Column in which the error occurred //////////////////////////////////////////////////////////////////////////////// @@ -127,8 +124,7 @@ namespace triagens { /// @brief Create a new instance //////////////////////////////////////////////////////////////////////////////// - ParserWrapper (const char *); - + ParserWrapper (const char*); //////////////////////////////////////////////////////////////////////////////// /// @brief Destroy the instance and free all associated memory @@ -136,60 +132,59 @@ namespace triagens { ~ParserWrapper (); - //////////////////////////////////////////////////////////////////////////////// /// @brief Parse the query passed //////////////////////////////////////////////////////////////////////////////// bool parse (); - //////////////////////////////////////////////////////////////////////////////// /// @brief Get a parse error that may have occurred //////////////////////////////////////////////////////////////////////////////// - ParseError *getParseError (); - + ParseError* getParseError (); //////////////////////////////////////////////////////////////////////////////// /// @brief Get the type of the query //////////////////////////////////////////////////////////////////////////////// - QL_ast_query_type_e getQueryType (); + QL_ast_query_type_e getQueryType (); //////////////////////////////////////////////////////////////////////////////// /// @brief Create a select clause //////////////////////////////////////////////////////////////////////////////// - TRI_qry_select_t *getSelect (); + TRI_qry_select_t* getSelect (); //////////////////////////////////////////////////////////////////////////////// /// @brief Get the alias of the primary collection //////////////////////////////////////////////////////////////////////////////// - char *getPrimaryAlias (); - + char* getPrimaryAlias (); //////////////////////////////////////////////////////////////////////////////// /// @brief Get the name of the primary collection //////////////////////////////////////////////////////////////////////////////// - char *getPrimaryName (); + char* getPrimaryName (); +//////////////////////////////////////////////////////////////////////////////// +/// @brief Create joins +//////////////////////////////////////////////////////////////////////////////// + + TRI_select_join_t* getJoins (); //////////////////////////////////////////////////////////////////////////////// /// @brief Create a where clause //////////////////////////////////////////////////////////////////////////////// - TRI_qry_where_t *getWhere (); - + TRI_qry_where_t* getWhere (); //////////////////////////////////////////////////////////////////////////////// /// @brief Create an order clause //////////////////////////////////////////////////////////////////////////////// - TRI_qry_order_t *getOrder (); - + TRI_qry_order_t* getOrder (); //////////////////////////////////////////////////////////////////////////////// /// @brief Get the skip value @@ -197,31 +192,27 @@ namespace triagens { TRI_voc_size_t getSkip (); - //////////////////////////////////////////////////////////////////////////////// /// @brief Get the limit value //////////////////////////////////////////////////////////////////////////////// TRI_voc_ssize_t getLimit (); - private: //////////////////////////////////////////////////////////////////////////////// /// @brief Query string //////////////////////////////////////////////////////////////////////////////// - const char *_query; + const char* _query; - //////////////////////////////////////////////////////////////////////////////// /// @brief Parser context. This is a struct that is used extensively by the /// parser. It contains a pointer to the flex lexer, a pointer to the query's /// AST root nodes and state information for memory management (GC) //////////////////////////////////////////////////////////////////////////////// - QL_parser_context_t *_context; - + QL_parser_context_t* _context; //////////////////////////////////////////////////////////////////////////////// /// @brief Pointer to a parse error @@ -230,8 +221,7 @@ namespace triagens { /// error occurs. It will be freed automatically when the parser is destroyed. //////////////////////////////////////////////////////////////////////////////// - ParseError *_parseError; - + ParseError* _parseError; //////////////////////////////////////////////////////////////////////////////// /// @brief Flag if parsing has already taken place diff --git a/QL/ast-node.c b/QL/ast-node.c index e78edffbee..a28c4a1635 100644 --- a/QL/ast-node.c +++ b/QL/ast-node.c @@ -413,7 +413,7 @@ bool QLAstNodeIsRelationalOperator (QL_ast_node_t *node) { /// @brief return whether a node is a constant //////////////////////////////////////////////////////////////////////////////// -bool QLAstNodeIsBooleanizable (QL_ast_node_t *node) { +bool QLAstNodeIsBooleanizable (const QL_ast_node_t *node) { switch (node->_type) { case QLNodeValueBool: // case QLNodeValueString: // TODO diff --git a/QL/ast-node.h b/QL/ast-node.h index 8c6e90a07a..b8422cc5b7 100644 --- a/QL/ast-node.h +++ b/QL/ast-node.h @@ -242,7 +242,7 @@ bool QLAstNodeIsRelationalOperator (QL_ast_node_t *); /// @brief return whether a node is convertable into a bool value //////////////////////////////////////////////////////////////////////////////// -bool QLAstNodeIsBooleanizable (QL_ast_node_t *); +bool QLAstNodeIsBooleanizable (const QL_ast_node_t *); //////////////////////////////////////////////////////////////////////////////// diff --git a/QL/formatter.c b/QL/formatter.c index 1dbc97d97c..ce6e0a50d2 100644 --- a/QL/formatter.c +++ b/QL/formatter.c @@ -91,7 +91,7 @@ void QLFormatterPrintBlockEnd (QL_formatter_t *formatter,const char *name) { void QLFormatterPrintInt (QL_formatter_t *formatter,const char *name,uint64_t value) { QLFormatterPrintIndentation(formatter); - printf("%s: %llu\n",name,value); + //printf("%s: %llu\n",name,value); } diff --git a/QL/optimize.c b/QL/optimize.c index 366c54f4ee..4a58750627 100644 --- a/QL/optimize.c +++ b/QL/optimize.c @@ -578,20 +578,18 @@ QL_ast_query_select_type_e QLOptimizeGetSelectType (const QL_ast_query_t *query) //////////////////////////////////////////////////////////////////////////////// -/// @brief get the type of a query's WHERE condition +/// @brief get the type of a query's WHERE/ON condition //////////////////////////////////////////////////////////////////////////////// -QL_ast_query_where_type_e QLOptimizeGetWhereType (const QL_ast_query_t *query) { - QL_ast_node_t *whereNode = query->_where._base; - - if (whereNode == 0) { +QL_ast_query_where_type_e QLOptimizeGetWhereType (const QL_ast_node_t *node) { + if (node == 0) { // query does not have a WHERE part return QLQueryWhereTypeAlwaysTrue; } - if (QLAstNodeIsBooleanizable(whereNode)) { + if (QLAstNodeIsBooleanizable(node)) { // WHERE part is constant - if (QLOptimizeGetBool(whereNode)) { + if (QLOptimizeGetBool(node)) { // WHERE is always true return QLQueryWhereTypeAlwaysTrue; } diff --git a/QL/optimize.h b/QL/optimize.h index 7e7c367e78..de87110991 100644 --- a/QL/optimize.h +++ b/QL/optimize.h @@ -130,10 +130,10 @@ QL_ast_query_select_type_e QLOptimizeGetSelectType (const QL_ast_query_t*); //////////////////////////////////////////////////////////////////////////////// -/// @brief get the type of a query's WHERE condition +/// @brief get the type of a query's WHERE/ON condition //////////////////////////////////////////////////////////////////////////////// -QL_ast_query_where_type_e QLOptimizeGetWhereType (const QL_ast_query_t*); +QL_ast_query_where_type_e QLOptimizeGetWhereType (const QL_ast_node_t*); //////////////////////////////////////////////////////////////////////////////// diff --git a/Rest/AddressPort.cpp b/Rest/AddressPort.cpp index 17d4209bfe..de01e96c79 100644 --- a/Rest/AddressPort.cpp +++ b/Rest/AddressPort.cpp @@ -53,7 +53,23 @@ namespace triagens { bool AddressPort::split (string const& definition) { - size_t n = StringUtils::numEntries(definition, ":"); + if (definition.empty()) { + return false; + } + + if (definition[0] == '[') { + // ipv6 address + size_t find = definition.find("]:", 1); + + if (find != string::npos && find + 2 < definition.size()) { + address = definition.substr(1, find-1); + port = StringUtils::uint32(definition.substr(find+2)); + return true; + } + + } + + int n = StringUtils::numEntries(definition, ":"); if (n == 1) { address = ""; diff --git a/RestServer/AvocadoServer.cpp b/RestServer/AvocadoServer.cpp index 41e854f31a..2a6d340b3a 100644 --- a/RestServer/AvocadoServer.cpp +++ b/RestServer/AvocadoServer.cpp @@ -42,6 +42,7 @@ #include "Dispatcher/ApplicationServerDispatcher.h" #include "Dispatcher/DispatcherImpl.h" #include "HttpServer/HttpHandlerFactory.h" +#include "HttpServer/RedirectHandler.h" #include "Logger/Logger.h" #include "Rest/Initialise.h" #include "RestHandler/RestActionHandler.h" @@ -167,6 +168,10 @@ AvocadoServer::AvocadoServer (int argc, char** argv) _databasePath("/var/lib/avocado"), _vocbase(0) { _workingDirectory = "/var/tmp"; + +#ifdef _PKGDATADIR_ + _systemActionPath = string(_PKGDATADIR_) + "/js/system"; +#endif } //////////////////////////////////////////////////////////////////////////////// @@ -259,7 +264,7 @@ void AvocadoServer::buildApplicationServer () { // ............................................................................. additional["JAVASCRIPT Options"] - ("startup.directory", &_startupPath, "path to the directory containing the startup scripts") + ("startup.directory", &_startupPath, "path to the directory containing alternate startup scripts") ("startup.modules-path", &_startupModules, "one or more directories separated by semicolon") ("action.directory", &_actionPath, "path to the action directory, defaults to /_ACTIONS") ; @@ -300,6 +305,7 @@ void AvocadoServer::buildApplicationServer () { } if (_startupPath.empty()) { + LOGGER_INFO << "using built-in JavaScript startup files"; StartupLoader.defineScript("bootstrap/modules.js", JS_bootstrap_modules); StartupLoader.defineScript("bootstrap/print.js", JS_bootstrap_print); StartupLoader.defineScript("server/actions.js", JS_server_actions); @@ -308,6 +314,7 @@ void AvocadoServer::buildApplicationServer () { StartupLoader.defineScript("server/shell.js", JS_server_shell); } else { + LOGGER_INFO << "using JavaScript startup files at '" << _startupPath << "'"; StartupLoader.setDirectory(_startupPath); } @@ -335,13 +342,20 @@ void AvocadoServer::buildApplicationServer () { } ActionLoader.setDirectory(path); + + LOGGER_INFO << "using database action files at '" << path << "'"; } else { ActionLoader.setDirectory(_actionPath); + LOGGER_INFO << "using alternate action files at '" << _actionPath << "'"; } if (! _systemActionPath.empty()) { SystemActionLoader.setDirectory(_systemActionPath); + LOGGER_INFO << "using system action files at '" << _systemActionPath << "'"; + } + else { + LOGGER_INFO << "system actions are disabled, empty system action path"; } // ............................................................................. @@ -463,6 +477,8 @@ int AvocadoServer::startupServer () { adminFactory->addPrefixHandler(RestVocbaseBaseHandler::ACTION_PATH, RestHandlerCreator::createData, _vocbase); adminFactory->addPrefixHandler(RestVocbaseBaseHandler::SYSTEM_ACTION_PATH, RestHandlerCreator::createData, _vocbase); + adminFactory->addHandler("/", RedirectHandler::create, (void*) "/admin/index.html"); + _adminHttpServer = _applicationHttpServer->buildServer(adminFactory, adminPorts); } diff --git a/RestServer/install.h b/RestServer/install.h index c9d44b56d6..24516afed5 100644 --- a/RestServer/install.h +++ b/RestServer/install.h @@ -29,7 +29,8 @@ /// @page CompilingTOC /// ///
    -///
  1. @ref CompilingPrerequisites "Prerequisites"
  2. +///
  3. @ref CompilingPrerequisites
  4. +///
  5. @ref CompilingGeneral
  6. ///
//////////////////////////////////////////////////////////////////////////////// @@ -40,20 +41,119 @@ /// @copydoc CompilingTOC ///
/// -/// @anchor CompilingPrerequisites -/// @section Prerequisites +/// The following sections describe how to compile and build the AvocadoDB from +/// scratch. The AvocadoDB will compile on most Linux and Mac OS X systems. It +/// assumes that you use the GNU C++ compiler to compile the source. The +/// AvocadoDB has been tested with the GNU C++ compiler, but should compile with +/// any Posix compliant compiler. Please let us know, whether you successfully +/// compiled it with another C++ compiler. +/// +/// @section CompilingPrerequisites Basic System Requirements /// -/// In order to compile the AvocadoDB, you will need +/// Verify that your system contains /// -/// - a recent version of GCC / G++ -/// - a recent version of FLEX -/// - a recent version of BISON +/// - the GNU C++ compiler "g++" and standard C++ libraries +/// - the GNU autotools (autoconf, automake) +/// - the GNU make +/// - the GNU scanner generator FLEX +/// - the GNU parser generator BISON /// -/// - the libev in version 3 or 4 -/// - a recent version of the Google's V8 engine -/// - the readline library -/// - the ncurses library -/// - the boost header files +/// In addition you will need the following libraries +/// +/// - libev in version 3 or 4 +/// - Google's V8 engine +/// - the GNU readline library +/// - the GNU ncurses library in version 5 or 6 +/// - boost header files, at least version 1.33 +/// +/// Some distributions, for example Centos 5, provide only very out-dated +/// versions of FLEX, BISON, and the V8 engine. In that case you need to compile +/// newer versions of the programs and/or libraries. +/// +/// @section CompilingGeneral Compiling the AvocadoDB +/// +/// @subsection DownloadSource Download the Source +/// +/// Download the latest source using GIT: +/// +/// @LIT{git clone git://github.com/triAGENS/AvocadoDB.git} +/// +/// @subsection Prerequisites Prerequisites +/// +/// Install or download the prerequisites +/// +/// - boost development package (see www.boost.org), at least version 1.33 +/// - Google's V8 engine (see code.google.com/p/v8) +/// - libev (see software.schmorp.de/pkg/libev.html) +/// +/// Most linux systems already supply RPM or DEP for there packages. Please note +/// that you have to install the development packages. +/// +/// @subsection Setup Setup +/// +/// Switch into the AvocadoDB directory +/// +/// @LIT{cd AvocadoDB} +/// +/// The source tarball contains a pre-generated "configure" script. You can +/// regenerate this script by using the GNU auto tools. In order to do so, +/// execute +/// +/// @LIT{make setup} +/// +/// This will call aclocal, autoheader, automake, and autoconf in the correct +/// order. +/// +/// @subsection Configure Configure +/// +/// In order to configure the build environment execute +/// +/// @LIT{./configure} +/// +/// to setup the makefiles. This will check for the various system +/// characteristics and installed libraries. If the configure scripts fail to +/// find the boost library, check that C++ is installed and working and that the +/// boost-devel package was successfully installed. +/// +/// @subsection Compile Compile +/// +/// Compile the program by executing +/// +/// @LIT{make} +/// +/// This will compile the AvocadoDB and create a binary of the server in +/// +/// @LIT{./avocadodb} +/// +/// @subsection Test Test +/// +/// Check the binary by starting it using the command line. +/// +/// @LIT{./avocado --server.http-port 12345 /tmp/vocbase} +/// +/// This will start up the AvocadoDB and listen for HTTP requests on port 12345 +/// bound to any address. You should see the startup messages +/// +/// @verbinclude startup1 +/// +/// Use your favorite browser to access the URL +/// +/// @LIT{http://localhost:12345/version} +/// +/// This should produce a JSON object like +/// +/// @LIT{\{"server":"avocado"\,"version":"0.0.8 [exported]"\}} +/// +/// as result. +/// +/// @subsection Install Install +/// +/// Install everything by executing +/// +/// @LIT{make install} +/// +/// You must be root to do this or at least have write permission to the +/// corresponding directories. //////////////////////////////////////////////////////////////////////////////// // Local Variables: diff --git a/Scheduler/ListenTask.cpp b/Scheduler/ListenTask.cpp index 809566da8f..0054a01c1a 100644 --- a/Scheduler/ListenTask.cpp +++ b/Scheduler/ListenTask.cpp @@ -35,11 +35,13 @@ #include #include +#include #include #include #include +#include #include #include @@ -81,6 +83,17 @@ namespace triagens { bindSocket(); } + ListenTask::ListenTask (struct addrinfo *aip, bool reuseAddress) + : Task("ListenTask"), + readWatcher(0), + reuseAddress(reuseAddress), + address(""), + port(0), + listenSocket(0), + bound(false), + acceptFailures(0) { + bindSocket(aip); + } ListenTask::~ListenTask () { @@ -99,16 +112,6 @@ namespace triagens { - bool ListenTask::rebind () { - MUTEX_LOCKER(changeLock); - - if (bound) { - close(listenSocket); - } - - return bindSocket(); - } - // ----------------------------------------------------------------------------- // Task methods // ----------------------------------------------------------------------------- @@ -216,13 +219,30 @@ namespace triagens { // handle connection ConnectionInfo info; - +/* info.serverAddress = inet_ntoa(addr_out.sin_addr); info.serverPort = port; info.clientAddress = inet_ntoa(addr.sin_addr); info.clientPort = addr.sin_port; +*/ + // set client address and port + char host[NI_MAXHOST], serv[NI_MAXSERV]; + if (getnameinfo((sockaddr*) &addr, len, + host, sizeof(host), + serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV) == 0) { + info.clientAddress = string(host); + info.clientPort = addr.sin_port; + } + else { + info.clientAddress = inet_ntoa(addr.sin_addr); + info.clientPort = addr.sin_port; + } + + info.serverAddress = address; + info.serverPort = port; + return handleConnected(connfd, info); } @@ -235,12 +255,68 @@ namespace triagens { bool ListenTask::bindSocket () { bound = false; + listenSocket = -1; + + struct addrinfo *result, *aip; + struct addrinfo hints; + int error; - // create a new socket - listenSocket = socket(AF_INET, SOCK_STREAM, 0); + memset(&hints, 0, sizeof (struct addrinfo)); + hints.ai_family = AF_UNSPEC; // Allow IPv4 or IPv6 + hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV | AI_ALL; + hints.ai_socktype = SOCK_STREAM; - if (listenSocket < 0) { - LOGGER_ERROR << "socket failed with " << errno << " (" << strerror(errno) << ")"; + string portString = StringUtils::itoa(port); + + if (address.empty()) { + LOGGER_ERROR << "get any address"; + error = getaddrinfo(NULL, portString.c_str(), &hints, &result); + } + else { + error = getaddrinfo(address.c_str(), portString.c_str(), &hints, &result); + } + + if (error != 0) { + LOGGER_ERROR << "getaddrinfo for host: " << address.c_str() << " => " << gai_strerror(error); + return false; + } + + // Try all returned addresses until one works + for (aip = result; aip != NULL; aip = aip->ai_next) { + + // try to bind the address info pointer + if (bindSocket(aip)) { + // OK + break; + } + + } + + freeaddrinfo(result); + + return bound; + } + + + + bool ListenTask::bindSocket (struct addrinfo *aip) { + bound = false; + listenSocket = -1; + + // set address and port + char host[NI_MAXHOST], serv[NI_MAXSERV]; + if (getnameinfo(aip->ai_addr, aip->ai_addrlen, + host, sizeof(host), + serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV) == 0) { + + address = string(host); + port = StringUtils::int32(string(serv)); + + LOGGER_TRACE << "bind to address '" << address << "' port '" << string(serv) << "'"; + } + + listenSocket = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol); + if (listenSocket == -1) { return false; } @@ -248,57 +324,19 @@ namespace triagens { if (reuseAddress) { int opt = 1; - if (setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&opt), sizeof(opt)) == -1) { + if (setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast (&opt), sizeof (opt)) == -1) { LOGGER_ERROR << "setsockopt failed with " << errno << " (" << strerror(errno) << ")"; return false; } LOGGER_TRACE << "reuse address flag set"; } - - // bind to any address - sockaddr_in addr; - - if (address.empty()) { - memset(&addr, 0, sizeof(addr)); - - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_ANY); - addr.sin_port = htons(port); - } - - // bind to a given address - else { - size_t length; - char* a = TRI_GetHostByName(address.c_str(), &length); - - if (a == 0) { - LOGGER_ERROR << "cannot resolve hostname: " << errno << " (" << strerror(errno) << ")"; - return false; - } - - if (sizeof(addr.sin_addr.s_addr) < length) { - LOGGER_ERROR << "IPv6 address are not allowed"; - return false; - } - - // bind socket to an address - memset(&addr, 0, sizeof(addr)); - - addr.sin_family = AF_INET; - memcpy(&(addr.sin_addr.s_addr), a, length); - addr.sin_port = htons(port); - - TRI_Free(a); - } - - int res = bind(listenSocket, (const sockaddr*) &addr, sizeof(addr)); - + + int res = bind(listenSocket, aip->ai_addr, aip->ai_addrlen); if (res < 0) { - close(listenSocket); - LOGGER_ERROR << "bind failed with " << errno << " (" << strerror(errno) << ")"; - + (void) close(listenSocket); + listenSocket = -1; return false; } @@ -316,7 +354,7 @@ namespace triagens { // set socket to non-blocking bool ok = TRI_SetNonBlockingSocket(listenSocket); - if (! ok) { + if (!ok) { close(listenSocket); LOGGER_ERROR << "cannot switch to non-blocking: " << errno << " (" << strerror(errno) << ")"; @@ -327,7 +365,7 @@ namespace triagens { // set close on exit ok = TRI_SetCloseOnExecSocket(listenSocket); - if (! ok) { + if (!ok) { close(listenSocket); LOGGER_ERROR << "cannot set close-on-exit: " << errno << " (" << strerror(errno) << ")"; @@ -339,5 +377,6 @@ namespace triagens { return true; } + } } diff --git a/Scheduler/ListenTask.h b/Scheduler/ListenTask.h index ffd24db608..5fb8844647 100644 --- a/Scheduler/ListenTask.h +++ b/Scheduler/ListenTask.h @@ -29,6 +29,8 @@ #ifndef TRIAGENS_FYN_REST_LISTEN_TASK_H #define TRIAGENS_FYN_REST_LISTEN_TASK_H 1 +#include + #include "Scheduler/Task.h" #include @@ -54,17 +56,23 @@ namespace triagens { public: //////////////////////////////////////////////////////////////////////////////// - /// @brief listen to given address and port + /// @brief listen to given address and port (deprecated) //////////////////////////////////////////////////////////////////////////////// ListenTask (string const& address, int port, bool reuseAddress); //////////////////////////////////////////////////////////////////////////////// - /// @brief listen to given port + /// @brief listen to given port (deprecated) //////////////////////////////////////////////////////////////////////////////// ListenTask (int port, bool reuseAddress); + //////////////////////////////////////////////////////////////////////////////// + /// @brief listen to given adress info pointer + //////////////////////////////////////////////////////////////////////////////// + + ListenTask (struct addrinfo *aip, bool reuseAddress); + public: //////////////////////////////////////////////////////////////////////////////// @@ -73,15 +81,6 @@ namespace triagens { bool isBound () const; - //////////////////////////////////////////////////////////////////////////////// - /// @brief try to rebind to port - /// - /// Note that this method can only be called before the task has been - /// registered. - //////////////////////////////////////////////////////////////////////////////// - - bool rebind (); - protected: //////////////////////////////////////////////////////////////////////////////// @@ -132,11 +131,12 @@ namespace triagens { private: bool bindSocket (); + bool bindSocket (struct addrinfo *aip); private: bool reuseAddress; - string const address; - int const port; + string address; + int port; socket_t listenSocket; bool bound; diff --git a/V8/v8-debug-shell.cpp b/V8/v8-debug-shell.cpp index da67976c52..a00d8e0f6b 100644 --- a/V8/v8-debug-shell.cpp +++ b/V8/v8-debug-shell.cpp @@ -41,6 +41,7 @@ #include "v8-shell.h" #include "v8-utils.h" #include "v8-vocbase.h" +#include "v8-conv.h" using namespace v8; diff --git a/VocBase/cursor.c b/VocBase/cursor.c deleted file mode 100644 index c47fde8ccd..0000000000 --- a/VocBase/cursor.c +++ /dev/null @@ -1,400 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// @brief cursors and result sets -/// -/// @file -/// -/// DISCLAIMER -/// -/// Copyright 2010-2012 triagens GmbH, Cologne, Germany -/// -/// 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. -/// -/// Copyright holder is triAGENS GmbH, Cologne, Germany -/// -/// @author Jan Steemann -/// @author Copyright 2012, triagens GmbH, Cologne, Germany -//////////////////////////////////////////////////////////////////////////////// - -#include "cursor.h" - -//////////////////////////////////////////////////////////////////////////////// -/// @def TRI_RESULTSET_INIT_SIZE -/// -/// initial data size (in bytes) in each result set -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_RESULTSET_INIT_SIZE 256 - -//////////////////////////////////////////////////////////////////////////////// -/// @def TRI_RESULTSET_GROWTH_FACTOR -/// -/// percentual growth factor for data in result sets -/// if a new allocation has to be made, the result set will grow by at least -/// this factor. The intention of this is to reduce the number of malloc calls -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_RESULTSET_GROWTH_FACTOR 0.1 - - -// ----------------------------------------------------------------------------- -// --SECTION-- result sets -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup VocBase -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief prepare next element in a single result set -//////////////////////////////////////////////////////////////////////////////// - -TRI_resultset_data_t *NextSingleResultset(TRI_resultset_t *resultset) { - TRI_resultset_data_t *current; - - assert(resultset->_type == RESULTSET_TYPE_SINGLE); - - if (resultset->_position == 0) { - resultset->_current = resultset->_data; - } - - current = resultset->_current; - resultset->_current += sizeof(TRI_doc_mptr_t *); - - ++resultset->_position; - - assert(resultset->_position < resultset->_length); - - return current; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief prepare next element in a multi result set -//////////////////////////////////////////////////////////////////////////////// - -TRI_resultset_data_t *NextMultiResultset(TRI_resultset_t *resultset) { - TRI_resultset_data_t *current; - TRI_resultset_element_multi_t *data; - TRI_voc_size_t n; - TRI_doc_mptr_t **documents; - - assert(resultset->_type == RESULTSET_TYPE_MULTI); - - if (resultset->_position == 0) { - resultset->_current = resultset->_data; - } - current = resultset->_current; - - data = (TRI_resultset_element_multi_t *) resultset->_current; - n = data->_num; - documents = data->_documents; - resultset->_current += sizeof(TRI_voc_size_t) + n * sizeof(TRI_doc_mptr_t *); - - ++resultset->_position; - - assert(resultset->_position < resultset->_length); - - return current; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief free common data structures in the result set -//////////////////////////////////////////////////////////////////////////////// - -static void FreeResultset(TRI_resultset_t *resultset) { - TRI_Free(resultset->_alias); - - TRI_Free(resultset->_data); - - // free result set itself - TRI_Free(resultset); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief free special data structures for single result sets -//////////////////////////////////////////////////////////////////////////////// - -static void FreeSingleResultset(TRI_resultset_t *resultset) { - FreeResultset(resultset); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief free special data structures for multi result sets -//////////////////////////////////////////////////////////////////////////////// - -static void FreeMultiResultset(TRI_resultset_t *resultset) { - FreeResultset(resultset); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief increase the data storage size of a result size -/// -/// the data size will grow by at least TRI_RESULTSET_GROWTH_FACTOR -//////////////////////////////////////////////////////////////////////////////// - -static bool IncreaseStorageResultset(TRI_resultset_t *resultset, size_t size) { - TRI_resultset_data_t *data; - size_t newSize = resultset->_storageAllocated + size; - - if (resultset->_data == 0) { - // if result set is broken after a failed realloc, we must exit early - return false; - } - - // increase by at least TRI_RESULTSET_GROWTH_FACTOR - if (newSize < (size_t) (resultset->_storageAllocated * TRI_RESULTSET_GROWTH_FACTOR)) { - newSize = (size_t) resultset->_storageAllocated * TRI_RESULTSET_GROWTH_FACTOR; - } - - // TODO: wrap realloc - data = (TRI_resultset_data_t *) realloc(resultset->_data, newSize); - if (data == 0) { - return false; - } - - resultset->_data = data; - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief add a single document to a single result set -//////////////////////////////////////////////////////////////////////////////// - -bool TRI_AddDocumentSingleResultset(TRI_resultset_t *resultset, const TRI_doc_mptr_t *document) { - size_t storageNeeded = sizeof(TRI_doc_mptr_t *); - - assert(resultset->_type == RESULTSET_TYPE_SINGLE); - - if (resultset->_storageUsed + storageNeeded < resultset->_storageAllocated) { - if (IncreaseStorageResultset(resultset, storageNeeded)) { - // could not get any more memory => error - return false; - } - } - - memcpy(resultset->_data + resultset->_storageUsed, document, sizeof(TRI_doc_mptr_t *)); - resultset->_storageUsed += storageNeeded; - - ++resultset->_length; - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief add multiple documents to a multiple result set -//////////////////////////////////////////////////////////////////////////////// - -bool TRI_AddDocumentsMultiResultset(TRI_resultset_t *resultset, const TRI_voc_size_t n, - const TRI_doc_mptr_t **documents) { - size_t storageNeeded = sizeof(TRI_voc_size_t) + n * sizeof(TRI_doc_mptr_t *); - - assert(resultset->_type == RESULTSET_TYPE_MULTI); - - if (resultset->_storageUsed + storageNeeded < resultset->_storageAllocated) { - if (IncreaseStorageResultset(resultset, storageNeeded)) { - // could not get any more memory => error - return false; - } - } - - memcpy(resultset->_data + resultset->_storageUsed, &n, sizeof(TRI_voc_size_t)); - resultset->_storageUsed += sizeof(TRI_voc_size_t); - - memcpy(resultset->_data + resultset->_storageUsed, documents, n); - resultset->_storageUsed += n * sizeof(TRI_doc_mptr_t *); - - ++resultset->_length; - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief create a new result set -//////////////////////////////////////////////////////////////////////////////// - -TRI_resultset_t *TRI_CreateResultset(const TRI_resultset_type_e type, const char *alias) { - TRI_resultset_t *resultset = (TRI_resultset_t *) TRI_Allocate(sizeof(TRI_resultset_t)); - - if (resultset == 0) { - return 0; - } - - resultset->_alias = TRI_DuplicateString(alias); - if (resultset->_alias == 0) { - TRI_Free(resultset); - return 0; - } - - // init storage - resultset->_data = (TRI_resultset_data_t *) - TRI_Allocate(TRI_RESULTSET_INIT_SIZE * sizeof(TRI_resultset_data_t *)); - - if (resultset->_data == 0) { - TRI_Free(resultset->_alias); - TRI_Free(resultset); - return 0; - } - - resultset->_storageAllocated = TRI_RESULTSET_INIT_SIZE; - resultset->_storageUsed = 0; - - resultset->_type = type; - resultset->_length = 0; - resultset->_position = 0; - - // setup function pointers - if (type == RESULTSET_TYPE_SINGLE) { - resultset->next = NextSingleResultset; - resultset->free = FreeSingleResultset; - } - else if (type == RESULTSET_TYPE_MULTI) { - resultset->next = NextMultiResultset; - resultset->free = FreeMultiResultset; - } - else { - assert(false); - } - - return resultset; -} - - -// ----------------------------------------------------------------------------- -// --SECTION-- cursors -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @brief free a cursor -//////////////////////////////////////////////////////////////////////////////// - -static void FreeCursor(TRI_cursor_t *cursor) { - size_t i = cursor->_resultsets._length; - - // free individual result sets (backwards, to save memmove calls in vector implementation - if (i > 0) { - while (true) { - i--; - FreeResultset((TRI_resultset_t *) cursor->_resultsets._buffer[i]); - if (i == 0) { - break; - } - } - } - - // free results vector - TRI_DestroyVectorPointer(&cursor->_currentData->_data); - TRI_Free(cursor->_currentData); - - // free result sets vector - TRI_DestroyVectorPointer(&cursor->_resultsets); - - // free cursor itself - TRI_Free(cursor); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief returns true if the cursor has more elements -//////////////////////////////////////////////////////////////////////////////// - -static inline bool HasNextCursor(const TRI_cursor_t *cursor) { - return (cursor->_position < cursor->_length); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief returns next element for the cursor -//////////////////////////////////////////////////////////////////////////////// - -TRI_resultset_row_t* NextCursor(TRI_cursor_t *cursor) { - size_t i; - TRI_resultset_data_t *data; - TRI_resultset_t *resultset; - - if (!HasNextCursor(cursor)) { - return 0; - } - - // iterate over all result sets in cursor - for (i = 0; i < cursor->_resultsets._length; i++) { - resultset = (TRI_resultset_t *) cursor->_resultsets._buffer[i]; - - // set data pointer for result set - data = resultset->next(resultset); - cursor->_currentData->_data._buffer[i] = data; - } - - ++cursor->_position; - return cursor->_currentData; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief add a result set to a cursor -//////////////////////////////////////////////////////////////////////////////// - -static void AddResultsetCursor(TRI_cursor_t *cursor, const TRI_resultset_t *resultset) { - TRI_PushBackVectorPointer(&cursor->_resultsets, (TRI_resultset_t *) resultset); - - // start with 0 pointer - TRI_PushBackVectorPointer(&cursor->_currentData->_data, 0); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief create a new cursor -//////////////////////////////////////////////////////////////////////////////// - -TRI_cursor_t *TRI_CreateCursor(TRI_rc_context_t *context, TRI_qry_select_t *select) { - TRI_cursor_t *cursor = (TRI_cursor_t *) TRI_Allocate(sizeof(TRI_cursor_t)); - - if (cursor == 0) { - return 0; - } - - cursor->_currentData = (TRI_resultset_row_t *) TRI_Allocate(sizeof(TRI_resultset_row_t)); - if (cursor->_currentData == 0) { - TRI_Free(cursor); - return 0; - } - - // init row result sets vector - TRI_InitVectorPointer(&cursor->_currentData->_data); - - // init result sets vector - TRI_InitVectorPointer(&cursor->_resultsets); - - // store context - cursor->_context = context; - cursor->_select = select; - - // setup function pointers - cursor->next = NextCursor; - cursor->hasNext = HasNextCursor; - cursor->free = FreeCursor; - cursor->addResultset = AddResultsetCursor; - - // init positional data - cursor->_length = 0; - cursor->_position = 0; - - return cursor; -} - - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - - -// Local Variables: -// mode: outline-minor -// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)" -// End: - diff --git a/VocBase/join.c b/VocBase/join.c index 95f9dcd9cd..bf8742c357 100644 --- a/VocBase/join.c +++ b/VocBase/join.c @@ -25,7 +25,7 @@ /// @author Copyright 2012, triagens GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// -#include "join.h" +#include "VocBase/join.h" //////////////////////////////////////////////////////////////////////////////// @@ -34,226 +34,82 @@ //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// -/// @brief free join data feeder +/// @brief Free join part memory //////////////////////////////////////////////////////////////////////////////// -static void FreeFeeder(TRI_join_feeder_t *feeder) { -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief init join data feeder -//////////////////////////////////////////////////////////////////////////////// - -static void InitFeeder(TRI_join_feeder_t *feeder) { - TRI_sim_collection_t *collection; - TRI_doc_mptr_t *document; - - collection = (TRI_sim_collection_t *) feeder->_collection; - if (collection->_primaryIndex._nrAlloc == 0) { - feeder->_start = 0; - feeder->_end = 0; - feeder->_current = 0; - return; +static void FreePart (TRI_join_part_t* part) { + if (part->_alias) { + TRI_Free(part->_alias); } - feeder->_start = (void **) collection->_primaryIndex._table; - feeder->_end = (void **) (feeder->_start + collection->_primaryIndex._nrAlloc); - - // collections contain documents in a hash table - // some of the entries are empty, and some contain deleted documents - // it is invalid to use every entry from the hash table but the invalid documents - // must be skipped. - // adjust starts to first valid document in collection - while (feeder->_start < feeder->_end) { - document = (TRI_doc_mptr_t*) *(feeder->_start); - if (document != 0 && !document->_deletion) { - break; - } - feeder->_start++; + if (part->_collectionName) { + TRI_Free(part->_collectionName); } - while (feeder->_end > feeder->_start) { - document = (TRI_doc_mptr_t*) *(feeder->_end - 1); - if (document != 0 && !document->_deletion) { - break; - } - feeder->_end--; - } - feeder->rewind(feeder); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief rewind join data feeder -//////////////////////////////////////////////////////////////////////////////// - -static void RewindFeeder(TRI_join_feeder_t *feeder) { - feeder->_current = feeder->_start; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief get current item from join data feeder and advance next pointer -//////////////////////////////////////////////////////////////////////////////// - -TRI_doc_mptr_t *CurrentFeeder(TRI_join_feeder_t *feeder) { - TRI_doc_mptr_t *document; - - while (feeder->_current < feeder->_end) { - document = (TRI_doc_mptr_t*) *(feeder->_current); - feeder->_current++; - if (document && document->_deletion == 0) { - return document; - } - } - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief get next item from join data feeder and advance next pointer -//////////////////////////////////////////////////////////////////////////////// - -TRI_doc_mptr_t *NextFeeder(TRI_join_feeder_t *feeder) { - TRI_doc_mptr_t *document; - - while (feeder->_current < feeder->_end) { - feeder->_current++; - document = (TRI_doc_mptr_t*) *(feeder->_current); - if (document && document->_deletion == 0) { - return document; - } - } - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief free a join part -//////////////////////////////////////////////////////////////////////////////// - -static void FreePartJoin(TRI_join_part_t *part) { - part->_feeder->free(part->_feeder); - TRI_Free(part->_feeder); TRI_Free(part); } //////////////////////////////////////////////////////////////////////////////// -/// @brief add a join part to a join +/// @brief Free join memory //////////////////////////////////////////////////////////////////////////////// -void TRI_AddPartJoin(TRI_join_t *join, const TRI_join_type_e type, TRI_resultset_t *resultset, TRI_sim_collection_t *collection) { - TRI_join_part_t *part; - TRI_join_feeder_t *feeder; - - part = (TRI_join_part_t *) TRI_Allocate(sizeof(TRI_join_part_t)); - if (part == 0) { - return; +static void FreeSelectJoin (TRI_select_join_t* join) { + TRI_join_part_t* part; + size_t i; + + for (i = 0; i < join->_parts._length; i++) { + part = (TRI_join_part_t*) join->_parts._buffer[i]; + part->free(part); } - feeder = (TRI_join_feeder_t *) TRI_Allocate(sizeof(TRI_join_feeder_t)); - if (feeder == 0) { - TRI_Free(part); - return; - } - - feeder->_collection = collection; - feeder->init = InitFeeder; - feeder->rewind = RewindFeeder; - feeder->current = CurrentFeeder; - feeder->next = NextFeeder; - feeder->free = FreeFeeder; - - feeder->init(feeder); - - part->_type = type; - part->_resultset = resultset; - part->_feeder = feeder; - part->free = FreePartJoin; - - TRI_PushBackVectorPointer(&join->_parts, part); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief free join memory -//////////////////////////////////////////////////////////////////////////////// - -static void FreeJoin(TRI_join_t *join) { - TRI_join_part_t *part; - size_t n = join->_parts._length; - - if (n > 0) { - while (true) { - n--; - part = join->_parts._buffer[n]; - part->free(part); - if (n == 0) { - break; - } - } - } TRI_DestroyVectorPointer(&join->_parts); TRI_Free(join); } //////////////////////////////////////////////////////////////////////////////// -/// @brief initialize a join +/// @brief Add a part to a select join //////////////////////////////////////////////////////////////////////////////// -TRI_join_t *TRI_CreateJoin() { - TRI_join_t *join = (TRI_join_t*) TRI_Allocate(sizeof(TRI_join_t)); +bool TRI_AddPartSelectJoin (TRI_select_join_t* join, const TRI_join_type_e type, + TRI_qry_where_t* condition, char* collectionName, + char* alias) { + + TRI_join_part_t* part; + + assert(join != 0); + part = (TRI_join_part_t*) TRI_Allocate(sizeof(TRI_join_part_t)); - if (join == 0) { - return 0; + if (part == 0) { + return false; } + + part->_type = type; + part->_condition = condition; + part->_collection = 0; + part->_collectionName = TRI_DuplicateString(collectionName); + part->_alias = TRI_DuplicateString(alias); + part->free = FreePart; - TRI_InitVectorPointer(&join->_parts); - - join->free = FreeJoin; - - return join; + TRI_PushBackVectorPointer(&join->_parts, part); + return true; } //////////////////////////////////////////////////////////////////////////////// -/// @brief execute joins +/// @brief Create a new join //////////////////////////////////////////////////////////////////////////////// -void TRI_ExecuteJoin(TRI_join_t *join) { - size_t numJoins; - size_t current; - TRI_join_feeder_t *feeder; - TRI_doc_mptr_t *document; - size_t numEval = 0; +TRI_select_join_t* TRI_CreateSelectJoin (void) { + TRI_select_join_t* join; - numJoins = join->_parts._length - 1; - current = numJoins; - - // actual join loop - implemented as nested loop join - // it currently does not use indexes etc. so the performance is as worst as can be - - feeder = ((TRI_join_part_t *) join->_parts._buffer[current])->_feeder; -JOIN_NEXT: - document = feeder->current(feeder); - if (document) { - numEval++; - goto JOIN_NEXT; - } - -JOIN_REPEAT: - if (current == 0) { - goto JOIN_END; + join = (TRI_select_join_t*) TRI_Allocate(sizeof(TRI_select_join_t)); + if (join == NULL) { + return NULL; } - feeder->rewind(feeder); - --current; - feeder = ((TRI_join_part_t *) join->_parts._buffer[current])->_feeder; - document = feeder->next(feeder); - if (document) { - current = numJoins; - feeder = ((TRI_join_part_t *) join->_parts._buffer[current])->_feeder; - goto JOIN_NEXT; - } - goto JOIN_REPEAT; - assert(false); + TRI_InitVectorPointer(&join->_parts); + join->free = FreeSelectJoin; -JOIN_END: - printf("JOIN NUM EVAL: %lu\n",numEval); + return join; } //////////////////////////////////////////////////////////////////////////////// @@ -266,4 +122,3 @@ JOIN_END: // outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)" // End: - diff --git a/VocBase/join.h b/VocBase/join.h index 0b246cae34..cff1866dd3 100644 --- a/VocBase/join.h +++ b/VocBase/join.h @@ -1,5 +1,5 @@ //////////////////////////////////////////////////////////////////////////////// -/// @brief joins +/// @brief %BRIEF% /// /// @file /// @@ -25,11 +25,14 @@ /// @author Copyright 2012, triagens GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// -#ifndef TRIAGENS_STORAGE_DURHAM_JOIN -#define TRIAGENS_STORAGE_DURHAM_JOIN +#ifndef TRIAGENS_DURHAM_VOC_BASE_JOIN_H +#define TRIAGENS_DURHAM_VOC_BASE_JOIN_H 1 -#include "simple-collection.h" -#include "cursor.h" +#include +#include +#include + +#include "VocBase/query.h" #ifdef __cplusplus extern "C" { @@ -46,71 +49,54 @@ extern "C" { typedef enum { JOIN_TYPE_PRIMARY, - JOIN_TYPE_LIST, JOIN_TYPE_INNER, - JOIN_TYPE_OUTER + JOIN_TYPE_OUTER, + JOIN_TYPE_LIST } TRI_join_type_e; -//////////////////////////////////////////////////////////////////////////////// -/// @brief input for join operator -//////////////////////////////////////////////////////////////////////////////// - -typedef struct TRI_join_feeder_s { - TRI_sim_collection_t *_collection; - void **_start; - void **_end; - void **_current; - - void (*init) (struct TRI_join_feeder_s*); - void (*rewind) (struct TRI_join_feeder_s*); - TRI_doc_mptr_t *(*current) (struct TRI_join_feeder_s*); - TRI_doc_mptr_t *(*next) (struct TRI_join_feeder_s*); - void (*free) (struct TRI_join_feeder_s*); -} -TRI_join_feeder_t; - //////////////////////////////////////////////////////////////////////////////// /// @brief join data structure //////////////////////////////////////////////////////////////////////////////// typedef struct TRI_join_part_s { - TRI_join_feeder_t *_feeder; // data source - TRI_resultset_t *_resultset; // result output TRI_join_type_e _type; + TRI_qry_where_t* _condition; + TRI_doc_collection_t* _collection; + char* _collectionName; + char* _alias; +// TRI_js_exec_context_t _context; void (*free) (struct TRI_join_part_s*); } TRI_join_part_t; //////////////////////////////////////////////////////////////////////////////// -/// @brief multi join container data structure +/// @brief join container data structure for select queries //////////////////////////////////////////////////////////////////////////////// -typedef struct TRI_join_s { +typedef struct TRI_select_join_s { TRI_vector_pointer_t _parts; - void (*free) (struct TRI_join_s*); + void (*free) (struct TRI_select_join_s*); } -TRI_join_t; +TRI_select_join_t; //////////////////////////////////////////////////////////////////////////////// -/// @brief add a join part to a join +/// @brief Add a part to a select join //////////////////////////////////////////////////////////////////////////////// - -void TRI_AddPartJoin(TRI_join_t *, const TRI_join_type_e, TRI_resultset_t *, TRI_sim_collection_t *); + +bool TRI_AddPartSelectJoin(TRI_select_join_t*, + const TRI_join_type_e, + TRI_qry_where_t*, + char*, + char*); //////////////////////////////////////////////////////////////////////////////// -/// @brief initialize a join +/// @brief Create a new join //////////////////////////////////////////////////////////////////////////////// -TRI_join_t *TRI_CreateJoin(void); - -//////////////////////////////////////////////////////////////////////////////// -/// @brief execute joins -//////////////////////////////////////////////////////////////////////////////// - -void TRI_ExecuteJoin(TRI_join_t *); +TRI_select_join_t* TRI_CreateSelectJoin (void); //////////////////////////////////////////////////////////////////////////////// /// @} diff --git a/VocBase/query.c b/VocBase/query.c index 77a849aa9d..1e624754db 100644 --- a/VocBase/query.c +++ b/VocBase/query.c @@ -30,6 +30,7 @@ #include "BasicsC/logging.h" #include "BasicsC/strings.h" #include "VocBase/simple-collection.h" +#include "VocBase/select-result.h" // ----------------------------------------------------------------------------- // --SECTION-- SELECT DOCUMENT @@ -1445,6 +1446,9 @@ TRI_rc_cursor_t* TRI_ExecuteQueryAql (TRI_query_t* query, TRI_rc_context_t* cont cond_fptr condition; order_fptr order; bool applyPostSkipLimit; + TRI_select_result_t* _select; + TRI_vector_pointer_t* _dataparts; + TRI_select_datapart_t* _datapart; skip = query->_skip; limit = query->_limit; @@ -1524,6 +1528,18 @@ TRI_rc_cursor_t* TRI_ExecuteQueryAql (TRI_query_t* query, TRI_rc_context_t* cont order = OrderDataGeneralQuery; } + +// stj +_dataparts = (TRI_vector_pointer_t*) TRI_Allocate(sizeof(TRI_vector_pointer_t)); +TRI_InitVectorPointer(_dataparts); +_datapart = TRI_CreateDataPart("fux", query->_primary, RESULT_PART_SINGLE); +TRI_PushBackVectorPointer(_dataparts, _datapart); +_select = TRI_CreateSelectResult(_dataparts); + +if (_select != NULL) { + _select->free(_select); +} + // ............................................................................. // construct a collection subset // ............................................................................. diff --git a/VocBase/select-result.c b/VocBase/select-result.c new file mode 100644 index 0000000000..5265e561aa --- /dev/null +++ b/VocBase/select-result.c @@ -0,0 +1,286 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief selects and select result sets +/// +/// @file +/// +/// DISCLAIMER +/// +/// Copyright 2010-2012 triagens GmbH, Cologne, Germany +/// +/// 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. +/// +/// Copyright holder is triAGENS GmbH, Cologne, Germany +/// +/// @author Jan Steemann +/// @author Copyright 2012, triagens GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// + +#include "VocBase/select-result.h" +#include "VocBase/query.h" + + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup VocBase +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Growth factor for select memory allocation +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_SELECT_RESULT_GROWTH_FACTOR 1.5 + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Free memory allocated for dataparts +//////////////////////////////////////////////////////////////////////////////// + +static void FreeDataPart(TRI_select_datapart_t* datapart) { + if (datapart->_alias != NULL) { + TRI_Free(datapart->_alias); + } + TRI_Free(datapart); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Create a new select datapart instance +//////////////////////////////////////////////////////////////////////////////// + +TRI_select_datapart_t* TRI_CreateDataPart(const char* alias, + const TRI_doc_collection_t* collection, + const TRI_select_data_e type) { + TRI_select_datapart_t* datapart; + + datapart = (TRI_select_datapart_t*) TRI_Allocate(sizeof(TRI_select_datapart_t)); + if (datapart == NULL) { + return NULL; + } + + datapart->_alias = TRI_DuplicateString(alias); + datapart->_collection = (TRI_doc_collection_t*) collection; + datapart->_type = type; + datapart->free = FreeDataPart; + + return datapart; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Free memory allocated for select result +//////////////////////////////////////////////////////////////////////////////// + +static void FreeSelectResult (TRI_select_result_t* _select) { + TRI_select_datapart_t* datapart; + size_t i; + + if (_select->_index._start != NULL) { + TRI_Free(_select->_index._start); + } + + if (_select->_documents._start != NULL) { + TRI_Free(_select->_documents._start); + } + + for (i = 0; i < _select->_dataParts->_length; i++) { + datapart = (TRI_select_datapart_t*) _select->_dataParts->_buffer[i]; + datapart->free(datapart); + } + + TRI_DestroyVectorPointer(_select->_dataParts); + TRI_Free(_select->_dataParts); + + TRI_Free(_select); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Initialise a select result +//////////////////////////////////////////////////////////////////////////////// + +static void InitSelectResult (TRI_select_result_t* _select, + TRI_vector_pointer_t* dataparts) { + _select->_index._numAllocated = 0; + _select->_index._numUsed = 0; + _select->_index._start = 0; + + _select->_documents._bytesAllocated = 0; + _select->_documents._bytesUsed = 0; + _select->_documents._start = 0; + _select->_documents._current = 0; + + _select->_dataParts = dataparts; + + _select->_numRows = 0; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Increase storage size for select result index +//////////////////////////////////////////////////////////////////////////////// + +static bool IncreaseIndexStorageSelectResult (TRI_select_result_t* _select, + const size_t numNeeded) { + void *start; + size_t newSize; + + newSize = (size_t) _select->_index._numAllocated + numNeeded; + if (newSize < + (size_t) (_select->_index._numAllocated * TRI_SELECT_RESULT_GROWTH_FACTOR)) { + newSize = (size_t) (_select->_index._numAllocated * TRI_SELECT_RESULT_GROWTH_FACTOR); + } + + start = realloc(_select->_index._start, newSize * sizeof(void *)); + if (start == 0) { + return false; + } + _select->_index._numAllocated = newSize; + + _select->_index._start = start; + _select->_index._current = (uint8_t *) start + + (_select->_index._numUsed * sizeof(void *)); + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Increase storage size for select documents data +//////////////////////////////////////////////////////////////////////////////// + +static bool IncreaseDocumentsStorageSelectResult(TRI_select_result_t* _select, + size_t bytesNeeded) { + size_t newSize; + void* start; + + newSize = (size_t) _select->_documents._bytesAllocated + bytesNeeded; + if (newSize < (size_t) (_select->_documents._bytesAllocated * 1.5)) { + newSize = (size_t) (_select->_documents._bytesAllocated * 1.5); + } + + start = realloc(_select->_documents._start, newSize); + if (start == 0) { + return false; + } + + if (start != _select->_documents._start && _select->_documents._start != 0) { + // FIXME: adjust entries in index + assert(false); + } + _select->_documents._bytesAllocated = newSize; + + _select->_documents._start = start; + _select->_documents._current = (uint8_t *) start + _select->_documents._bytesUsed; + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Get the required storage size for a document result +//////////////////////////////////////////////////////////////////////////////// + +static size_t GetDocumentSizeSelectResult (const TRI_select_result_t* _select, + const TRI_vector_pointer_t* documents) { + TRI_vector_pointer_t* part; + size_t i, total; + + total = 0; + for (i = 0; i < documents->_length; i++) { + total += sizeof(TRI_select_size_t); + part = (TRI_vector_pointer_t*) documents->_buffer[i]; + total += sizeof(TRI_doc_mptr_t*) * part->_length; + } + + return total; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Add a document to the result set +//////////////////////////////////////////////////////////////////////////////// + +bool TRI_AddDocumentSelectResult (TRI_select_result_t* _select, + TRI_vector_pointer_t* documents) { + TRI_select_size_t* numPtr; + TRI_doc_mptr_t** dataPtr; + void* startPtr; + TRI_vector_pointer_t* part; + size_t numNeeded; + size_t bytesNeeded; + size_t i, j; + + numNeeded = documents->_length; + if (_select->_index._numUsed + documents->_length > _select->_index._numAllocated) { + if (!IncreaseIndexStorageSelectResult(_select, numNeeded)) { + return false; + } + } + + bytesNeeded = GetDocumentSizeSelectResult(_select, documents); + if (_select->_documents._bytesUsed + bytesNeeded > _select->_documents._bytesAllocated) { + if (!IncreaseDocumentsStorageSelectResult(_select, bytesNeeded)) { + return false; + } + } + + // store pointer to document + startPtr = _select->_index._current; + dataPtr = (TRI_doc_mptr_t**) startPtr; + *dataPtr++ = startPtr; + _select->_index._current = (void*) dataPtr; + _select->_index._numUsed++; + + // store document data + startPtr = _select->_documents._current; + numPtr = (TRI_select_size_t*) startPtr; + for (i = 0; i < documents->_length; i++) { + part = (TRI_vector_pointer_t*) documents->_buffer[i]; + *numPtr++ = part->_length; + dataPtr = (TRI_doc_mptr_t**) numPtr; + for (j = 0; j < part->_length; j++) { + *dataPtr++ = (TRI_doc_mptr_t*) part->_buffer[j]; + } + numPtr = (TRI_select_size_t*) dataPtr; + } + + _select->_documents._bytesUsed += bytesNeeded; + _select->_documents._current = numPtr; + + _select->_numRows++; + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Create a new select result +//////////////////////////////////////////////////////////////////////////////// + +TRI_select_result_t* TRI_CreateSelectResult (TRI_vector_pointer_t *dataparts) { + TRI_select_result_t* result; + + result = (TRI_select_result_t*) TRI_Allocate(sizeof(TRI_select_result_t)); + if (!result) { + return NULL; + } + InitSelectResult(result, dataparts); + + result->free = FreeSelectResult; + + return result; +} + + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + + +// Local Variables: +// mode: outline-minor +// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)" +// End: + + diff --git a/VocBase/cursor.h b/VocBase/select-result.h similarity index 50% rename from VocBase/cursor.h rename to VocBase/select-result.h index 05049434f5..ff4f1c0c22 100644 --- a/VocBase/cursor.h +++ b/VocBase/select-result.h @@ -1,5 +1,5 @@ //////////////////////////////////////////////////////////////////////////////// -/// @brief cursors and result sets +/// @brief select result /// /// @file /// @@ -25,16 +25,14 @@ /// @author Copyright 2012, triagens GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// -#ifndef TRIAGENS_DURHAM_VOC_BASE_CURSOR -#define TRIAGENS_DURHAM_VOC_BASE_CURSOR - -#include +#ifndef TRIAGENS_DURHAM_VOC_BASE_SELECT_RESULT_H +#define TRIAGENS_DURHAM_VOC_BASE_SELECT_RESULT_H 1 #include +#include #include -#include "VocBase/vocbase.h" -#include "VocBase/query.h" +#include "VocBase/document-collection.h" #ifdef __cplusplus extern "C" { @@ -46,133 +44,107 @@ extern "C" { //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// -/// @brief result set types -/// RESULTSET_TYPE_SINGLE means the result set will contain one element per -/// result row, RESULTSET_TYPE_MULTI means the result set will contain multiple -/// (0..n) elements per result row +/// @brief result part type (single document or multiple documents) //////////////////////////////////////////////////////////////////////////////// typedef enum { - RESULTSET_TYPE_UNDEFINED = 0, - - RESULTSET_TYPE_SINGLE, - RESULTSET_TYPE_MULTI -} -TRI_resultset_type_e; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief typedef for result set data -//////////////////////////////////////////////////////////////////////////////// - -typedef char TRI_resultset_data_t; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief result set element (base type) -//////////////////////////////////////////////////////////////////////////////// - -typedef struct TRI_resultset_element_s { - void *_data; - TRI_resultset_type_e _type; - void (*free) (struct TRI_resultset_element_s*); - bool (*toJavaScript) (struct TRI_resultset_element_s*, TRI_rc_result_t*, void*); + RESULT_PART_SINGLE = 0, + RESULT_PART_MULTI = 1 } -TRI_resultset_element_t; +TRI_select_data_e; + //////////////////////////////////////////////////////////////////////////////// -/// @brief single result set element +/// @brief typedef for number of rows in a select result //////////////////////////////////////////////////////////////////////////////// -typedef struct TRI_resultset_element_single_s { - TRI_doc_mptr_t *_document; -} -TRI_resultset_element_single_t; +typedef uint32_t TRI_select_size_t; //////////////////////////////////////////////////////////////////////////////// -/// @brief multiple result set element +/// @brief select input type //////////////////////////////////////////////////////////////////////////////// + +typedef struct TRI_select_feeder_s { + TRI_doc_collection_t* _collection; -typedef struct TRI_resultset_element_multi_s { - TRI_voc_size_t _num; - TRI_doc_mptr_t **_documents; -} -TRI_resultset_element_multi_t; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief result set type -//////////////////////////////////////////////////////////////////////////////// - -typedef struct TRI_resultset_s { - TRI_voc_size_t _length; - TRI_voc_size_t _position; - TRI_resultset_type_e _type; - char *_alias; - TRI_resultset_data_t *_data; - TRI_resultset_data_t *_current; - size_t _storageUsed; - size_t _storageAllocated; - - void (*free) (struct TRI_resultset_s*); - TRI_resultset_data_t *(*next)(struct TRI_resultset_s*); -// bool (*toJavaScript) (struct TRI_resultset_s*, void*); -} -TRI_resultset_t; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief result set row type -//////////////////////////////////////////////////////////////////////////////// - -typedef struct TRI_resultset_row_s { - TRI_vector_pointer_t _data; - bool (*toJavaScript) (struct TRI_resultset_row_s*, void*); + void (*init) (struct TRI_select_feeder_s*); + void (*rewind) (struct TRI_select_feeder_s*); + TRI_doc_mptr_t* (*current) (struct TRI_select_feeder_s*); + TRI_doc_mptr_t* (*next) (struct TRI_select_feeder_s*); } -TRI_resultset_row_t; +TRI_select_feeder_t; //////////////////////////////////////////////////////////////////////////////// -/// @brief cursor type +/// @brief select data parts type //////////////////////////////////////////////////////////////////////////////// -typedef struct TRI_cursor_s { - TRI_rc_context_t* _context; - TRI_qry_select_t* _select; +typedef struct TRI_select_datapart_s { + char* _alias; + TRI_doc_collection_t* _collection; + TRI_select_data_e _type; - TRI_vector_pointer_t _resultsets; - TRI_voc_size_t _length; - TRI_voc_size_t _position; - TRI_resultset_row_t *_currentData; - - void (*free) (struct TRI_cursor_s*); - TRI_resultset_row_t* (*next)(struct TRI_cursor_s*); - bool (*hasNext)(const struct TRI_cursor_s*); - void (*addResultset)(struct TRI_cursor_s*, const TRI_resultset_t*); + void (*free) (struct TRI_select_datapart_s*); } -TRI_cursor_t; +TRI_select_datapart_t; //////////////////////////////////////////////////////////////////////////////// -/// @brief add a single document to a single result set +/// @brief Create a new select datapart instance //////////////////////////////////////////////////////////////////////////////// -bool TRI_AddDocumentSingleResultset(TRI_resultset_t *, const TRI_doc_mptr_t *); - -//////////////////////////////////////////////////////////////////////////////// -/// @brief add multiple documents (0..n) to a multiple result set -//////////////////////////////////////////////////////////////////////////////// - -bool TRI_AddDocumentsMultiResultset(TRI_resultset_t *, const TRI_voc_size_t, - const TRI_doc_mptr_t **); +TRI_select_datapart_t* TRI_CreateDataPart(const char*, + const TRI_doc_collection_t*, + const TRI_select_data_e); //////////////////////////////////////////////////////////////////////////////// -/// @brief create a new result set +/// @brief document index within a select result //////////////////////////////////////////////////////////////////////////////// -TRI_resultset_t *TRI_CreateResultset(const TRI_resultset_type_e, const char*); +typedef struct TRI_select_result_index_s { + TRI_select_size_t _numAllocated; + TRI_select_size_t _numUsed; + void *_start; + void *_current; +} +TRI_select_result_index_t; //////////////////////////////////////////////////////////////////////////////// -/// @brief create a new cursor +/// @brief document storage within a select result //////////////////////////////////////////////////////////////////////////////// -TRI_cursor_t *TRI_CreateCursor(TRI_rc_context_t *, TRI_qry_select_t *); +typedef struct TRI_select_result_documents_s { + size_t _bytesAllocated; + size_t _bytesUsed; + void *_start; + void *_current; +} +TRI_select_result_documents_t; +//////////////////////////////////////////////////////////////////////////////// +/// @brief select result type +//////////////////////////////////////////////////////////////////////////////// + +typedef struct TRI_select_result_s { + TRI_select_size_t _numRows; + TRI_vector_pointer_t* _dataParts; + TRI_select_result_index_t _index; + TRI_select_result_documents_t _documents; + + void (*free) (struct TRI_select_result_s*); +} +TRI_select_result_t; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Add a document to the result set +//////////////////////////////////////////////////////////////////////////////// + +bool TRI_AddDocumentSelectResult (TRI_select_result_t*, TRI_vector_pointer_t*); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Create a new select result +//////////////////////////////////////////////////////////////////////////////// + +TRI_select_result_t* TRI_CreateSelectResult (TRI_vector_pointer_t*); //////////////////////////////////////////////////////////////////////////////// /// @} diff --git a/build.h b/build.h index b771ac150c..56a16268f7 100644 --- a/build.h +++ b/build.h @@ -1 +1 @@ -#define TRIAGENS_VERSION "0.0.8 [1311M]" +#define TRIAGENS_VERSION "0.0.8 [1316:1317M]" diff --git a/config/build_header.sh b/config/build_header.sh index ceb335b95c..c7e4255bbe 100755 --- a/config/build_header.sh +++ b/config/build_header.sh @@ -13,7 +13,7 @@ if test -d ${DIR}/.svn; then revision=`(cd $DIR && svnversion)` else if test ! -f "$INFO"; then - echo "WARNING: cannot open info file $INFO" + echo "INFO: cannot open info file $INFO, using exported" revision="exported" else revision=`grep 'Revision:' $INFO | awk '{print $2}'` diff --git a/m4/configure.basics b/m4/configure.basics index f9c3b7e94f..2c1573b57c 100644 --- a/m4/configure.basics +++ b/m4/configure.basics @@ -120,6 +120,7 @@ case $target in STATIC_LIBS="" DYNAMIC_LIBS="" LIBTOOL_LIBS="" + USE_DYLD="yes" ;; *) diff --git a/m4/external.v8 b/m4/external.v8 index 2f3feac09f..8520621536 100644 --- a/m4/external.v8 +++ b/m4/external.v8 @@ -6,17 +6,20 @@ dnl ---------------------------------------------------------------------------- V8_CPPFLAGS="" V8_LDFLAGS="" +V8_LIBS="" AC_ARG_WITH(v8, AS_HELP_STRING([--with-v8=DIR], [where the v8 library and includes are located]), [V8_CPPFLAGS="-I$withval/include" V8_LDFLAGS="-L$withval/lib" + V8_LIB_PATH="$withval/lib" V8="$withval"] ) AC_ARG_WITH(v8-lib, AS_HELP_STRING([--with-v8-lib=DIR], [where the v8 library is located]), - [V8_LDFLAGS="-L$withval"] + [V8_LDFLAGS="-L$withval" + V8_LIB_PATH="$withval"] ) TR_STATIC_ENABLE([v8]) @@ -75,6 +78,8 @@ if test "$cross_compiling" = yes; then : TRI_V8_VERSION="V8" AC_MSG_WARN([cannot compute V8 version number when cross compiling]) else + if test "x`type -t ac_fn_cxx_try_run`" = "xfunction" 2> /dev/null; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -85,8 +90,19 @@ int main (int, char**) { } _ACEOF - if test "x`type -t ac_fn_cxx_try_run`" = "xfunction" 2> /dev/null; then + + if test "x$V8_LIB_PATH" != x; then + if test "$USE_DYLD" = yes; then + save_DYLD_LIBRARY_PATH="$DYLD_LIBRARY_PATH" + DYLD_LIBRARY_PATH="$V8_LIB_PATH:$DYLD_LIBRARY_PATH" + else + save_LD_LIBRARY_PATH="$LD_LIBRARY_PATH" + DYLD_LIBRARY_PATH="$V8_LIB_PATH:$LD_LIBRARY_PATH" + fi + fi + AC_MSG_CHECKING([V8 version]) + if ac_fn_cxx_try_run "$LINENO" >conftest.output; then TRI_V8_VERSION=`cat conftest.output` AC_MSG_RESULT([$TRI_V8_VERSION]) @@ -94,12 +110,21 @@ _ACEOF AC_MSG_RESULT([failed]) AC_MSG_ERROR([Please install the V8 library from Google]) fi + + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.beam conftest.$ac_ext conftest.output + + if test "x$V8_LIB_PATH" != x; then + if test "$USE_DYLD" = yes; then + DYLD_LIBRARY_PATH="$save_DYLD_LIBRARY_PATH" + else + LD_LIBRARY_PATH="$save_LD_LIBRARY_PATH" + fi + fi else TRI_V8_VERSION="V8" AC_MSG_WARN([cannot compute V8 version number, old autoconf version]) fi fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.beam conftest.$ac_ext conftest.output dnl -----------------------------------------------------------------------------------------