mirror of https://gitee.com/bigwinds/arangodb
Backup with view (#10386)
* Commit and store view related data on create backup. * Fixes to upgrade on env-var. * Fixed CMakeLists.txt. * Changes to allow restore from 3.5 to 3.6. * Remove unnecessary code introduced in merge. * CHANGELOG:
This commit is contained in:
parent
caffa6a22e
commit
ebf3296e9c
|
@ -1,5 +1,10 @@
|
||||||
devel
|
devel
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
* Include ArangoSearch data in hotbackups.
|
||||||
|
|
||||||
|
* Allow to restore 3.5 hotbackups in 3.6.
|
||||||
|
|
||||||
* Fixed ArangoSearch index removes being discarded on commiting consolidation results with
|
* Fixed ArangoSearch index removes being discarded on commiting consolidation results with
|
||||||
pending removes after some segments under consolidation were already committed
|
pending removes after some segments under consolidation were already committed
|
||||||
|
|
||||||
|
|
|
@ -1384,3 +1384,6 @@ message(STATUS "building for git revision: ${ARANGODB_BUILD_REPOSITORY}")
|
||||||
# message(STATUS "${_variableName}=${${_variableName}}")
|
# message(STATUS "${_variableName}=${${_variableName}}")
|
||||||
# endforeach ()
|
# endforeach ()
|
||||||
# endif ()
|
# endif ()
|
||||||
|
|
||||||
|
add_custom_target(arangodb
|
||||||
|
DEPENDS arangod arangosh arangodump arangoexport arangobackup arangoimport arangorestore)
|
||||||
|
|
|
@ -873,6 +873,13 @@ target_link_libraries(arango_rocksdb arango_indexes)
|
||||||
target_link_libraries(arango_rocksdb arango_storage_engine_common)
|
target_link_libraries(arango_rocksdb arango_storage_engine_common)
|
||||||
target_link_libraries(arango_rocksdb boost_boost)
|
target_link_libraries(arango_rocksdb boost_boost)
|
||||||
|
|
||||||
|
if (USE_ENTERPRISE)
|
||||||
|
# this is required for hotbackup. Views need to be flushed.
|
||||||
|
target_include_directories(arango_rocksdb
|
||||||
|
PUBLIC ${IRESEARCH_INCLUDE}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
target_link_libraries(arango_storage_engine arango_cluster_engine)
|
target_link_libraries(arango_storage_engine arango_cluster_engine)
|
||||||
target_link_libraries(arango_storage_engine arango_cluster_methods)
|
target_link_libraries(arango_storage_engine arango_cluster_methods)
|
||||||
target_link_libraries(arango_storage_engine arango_mmfiles)
|
target_link_libraries(arango_storage_engine arango_mmfiles)
|
||||||
|
|
|
@ -3011,7 +3011,8 @@ arangodb::Result hotRestoreCoordinator(ClusterFeature& feature, VPackSlice const
|
||||||
using arangodb::methods::VersionResult;
|
using arangodb::methods::VersionResult;
|
||||||
#ifdef USE_ENTERPRISE
|
#ifdef USE_ENTERPRISE
|
||||||
// Will never be called in community
|
// Will never be called in community
|
||||||
if (!RocksDBHotBackup::versionTestRestore(meta._version)) {
|
bool autoUpgradeNeeded; // not actually used
|
||||||
|
if (!RocksDBHotBackup::versionTestRestore(meta._version, autoUpgradeNeeded)) {
|
||||||
return arangodb::Result(TRI_ERROR_HOT_RESTORE_INTERNAL,
|
return arangodb::Result(TRI_ERROR_HOT_RESTORE_INTERNAL,
|
||||||
"Version mismatch");
|
"Version mismatch");
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,31 +109,6 @@ struct LinkTrxState final : public arangodb::TransactionState::Cookie {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief compute the data path to user for iresearch data store
|
|
||||||
/// get base path from DatabaseServerFeature (similar to MMFilesEngine)
|
|
||||||
/// the path is hardcoded to reside under:
|
|
||||||
/// <DatabasePath>/<IResearchLink::type()>-<link id>
|
|
||||||
/// similar to the data path calculation for collections
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
irs::utf8_path getPersistedPath(arangodb::DatabasePathFeature const& dbPathFeature,
|
|
||||||
arangodb::iresearch::IResearchLink const& link) {
|
|
||||||
irs::utf8_path dataPath(dbPathFeature.directory());
|
|
||||||
static const std::string subPath("databases");
|
|
||||||
static const std::string dbPath("database-");
|
|
||||||
|
|
||||||
dataPath /= subPath;
|
|
||||||
dataPath /= dbPath;
|
|
||||||
dataPath += std::to_string(link.collection().vocbase().id());
|
|
||||||
dataPath /= arangodb::iresearch::DATA_SOURCE_TYPE.name();
|
|
||||||
dataPath += "-";
|
|
||||||
dataPath += std::to_string(link.collection().id()); // has to be 'id' since this can be a per-shard collection
|
|
||||||
dataPath += "_";
|
|
||||||
dataPath += std::to_string(link.id());
|
|
||||||
|
|
||||||
return dataPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief inserts ArangoDB document into an IResearch data store
|
/// @brief inserts ArangoDB document into an IResearch data store
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -241,6 +216,31 @@ bool readTick(irs::bytes_ref const& payload, TRI_voc_tick_t& tick) noexcept {
|
||||||
namespace arangodb {
|
namespace arangodb {
|
||||||
namespace iresearch {
|
namespace iresearch {
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief compute the data path to user for iresearch data store
|
||||||
|
/// get base path from DatabaseServerFeature (similar to MMFilesEngine)
|
||||||
|
/// the path is hardcoded to reside under:
|
||||||
|
/// <DatabasePath>/<IResearchLink::type()>-<link id>
|
||||||
|
/// similar to the data path calculation for collections
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
irs::utf8_path getPersistedPath(arangodb::DatabasePathFeature const& dbPathFeature,
|
||||||
|
arangodb::iresearch::IResearchLink const& link) {
|
||||||
|
irs::utf8_path dataPath(dbPathFeature.directory());
|
||||||
|
static const std::string subPath("databases");
|
||||||
|
static const std::string dbPath("database-");
|
||||||
|
|
||||||
|
dataPath /= subPath;
|
||||||
|
dataPath /= dbPath;
|
||||||
|
dataPath += std::to_string(link.collection().vocbase().id());
|
||||||
|
dataPath /= arangodb::iresearch::DATA_SOURCE_TYPE.name();
|
||||||
|
dataPath += "-";
|
||||||
|
dataPath += std::to_string(link.collection().id()); // has to be 'id' since this can be a per-shard collection
|
||||||
|
dataPath += "_";
|
||||||
|
dataPath += std::to_string(link.id());
|
||||||
|
|
||||||
|
return dataPath;
|
||||||
|
}
|
||||||
|
|
||||||
IResearchLink::IResearchLink(
|
IResearchLink::IResearchLink(
|
||||||
TRI_idx_iid_t iid,
|
TRI_idx_iid_t iid,
|
||||||
LogicalCollection& collection)
|
LogicalCollection& collection)
|
||||||
|
|
|
@ -29,10 +29,11 @@
|
||||||
#include "store/directory.hpp"
|
#include "store/directory.hpp"
|
||||||
#include "utils/utf8_path.hpp"
|
#include "utils/utf8_path.hpp"
|
||||||
|
|
||||||
|
#include "Indexes/Index.h"
|
||||||
#include "IResearchLinkMeta.h"
|
#include "IResearchLinkMeta.h"
|
||||||
#include "IResearchViewMeta.h"
|
#include "IResearchViewMeta.h"
|
||||||
#include "IResearchVPackComparer.h"
|
#include "IResearchVPackComparer.h"
|
||||||
#include "Indexes/Index.h"
|
#include "RestServer/DatabasePathFeature.h"
|
||||||
#include "Transaction/Status.h"
|
#include "Transaction/Status.h"
|
||||||
|
|
||||||
namespace arangodb {
|
namespace arangodb {
|
||||||
|
@ -333,6 +334,9 @@ class IResearchLink {
|
||||||
bool _createdInRecovery; // link was created based on recovery marker
|
bool _createdInRecovery; // link was created based on recovery marker
|
||||||
}; // IResearchLink
|
}; // IResearchLink
|
||||||
|
|
||||||
|
irs::utf8_path getPersistedPath(arangodb::DatabasePathFeature const& dbPathFeature,
|
||||||
|
arangodb::iresearch::IResearchLink const& link);
|
||||||
|
|
||||||
} // namespace iresearch
|
} // namespace iresearch
|
||||||
} // namespace arangodb
|
} // namespace arangodb
|
||||||
|
|
||||||
|
|
|
@ -28,8 +28,13 @@
|
||||||
#include "ApplicationFeatures/SupervisorFeature.h"
|
#include "ApplicationFeatures/SupervisorFeature.h"
|
||||||
#include "Basics/application-exit.h"
|
#include "Basics/application-exit.h"
|
||||||
#include "Basics/ScopeGuard.h"
|
#include "Basics/ScopeGuard.h"
|
||||||
|
#include "Basics/StaticStrings.h"
|
||||||
|
#include "Cluster/ClusterFeature.h"
|
||||||
#include "Cluster/ClusterFeature.h"
|
#include "Cluster/ClusterFeature.h"
|
||||||
#include "Cluster/ServerState.h"
|
#include "Cluster/ServerState.h"
|
||||||
|
#ifdef USE_ENTERPRISE
|
||||||
|
#include "Enterprise/StorageEngine/HotBackupFeature.h"
|
||||||
|
#endif
|
||||||
#include "FeaturePhases/AqlFeaturePhase.h"
|
#include "FeaturePhases/AqlFeaturePhase.h"
|
||||||
#include "GeneralServer/AuthenticationFeature.h"
|
#include "GeneralServer/AuthenticationFeature.h"
|
||||||
#include "Logger/LogMacros.h"
|
#include "Logger/LogMacros.h"
|
||||||
|
@ -85,10 +90,8 @@ void UpgradeFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
|
||||||
extern std::function<int()> * restartAction;
|
extern std::function<int()> * restartAction;
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
static std::string const UPGRADE_ENV = "ARANGODB_UPGRADE_DURING_RESTORE";
|
|
||||||
|
|
||||||
static int upgradeRestart() {
|
static int upgradeRestart() {
|
||||||
unsetenv(UPGRADE_ENV.c_str());
|
unsetenv(StaticStrings::UpgradeEnvName.c_str());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -103,11 +106,15 @@ void UpgradeFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
|
||||||
// variable at runtime and then does a restore. After the restart (with
|
// variable at runtime and then does a restore. After the restart (with
|
||||||
// the old data) the database upgrade is run and another restart is
|
// the old data) the database upgrade is run and another restart is
|
||||||
// happening afterwards with the environment variable being cleared.
|
// happening afterwards with the environment variable being cleared.
|
||||||
char* upgrade = getenv(UPGRADE_ENV.c_str());
|
char* upgrade = getenv(StaticStrings::UpgradeEnvName.c_str());
|
||||||
if (upgrade != nullptr) {
|
if (upgrade != nullptr) {
|
||||||
_upgrade = true;
|
_upgrade = true;
|
||||||
restartAction = new std::function<int()>();
|
restartAction = new std::function<int()>();
|
||||||
*restartAction = upgradeRestart;
|
*restartAction = upgradeRestart;
|
||||||
|
LOG_TOPIC("fdeae", INFO, Logger::STARTUP)
|
||||||
|
<< "Detected environment variable " << StaticStrings::UpgradeEnvName
|
||||||
|
<< " with value " << upgrade
|
||||||
|
<< " will perform database auto-upgrade and immediately restart.";
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (_upgrade && !_upgradeCheck) {
|
if (_upgrade && !_upgradeCheck) {
|
||||||
|
@ -150,6 +157,11 @@ void UpgradeFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
|
||||||
|
|
||||||
DatabaseFeature& database = server().getFeature<DatabaseFeature>();
|
DatabaseFeature& database = server().getFeature<DatabaseFeature>();
|
||||||
database.enableUpgrade();
|
database.enableUpgrade();
|
||||||
|
|
||||||
|
#ifdef USE_ENTERPRISE
|
||||||
|
HotBackupFeature& hotBackupFeature = server().getFeature<HotBackupFeature>();
|
||||||
|
hotBackupFeature.forceDisable();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpgradeFeature::prepare() {
|
void UpgradeFeature::prepare() {
|
||||||
|
|
|
@ -275,3 +275,7 @@ std::string const StaticStrings::RebootId("rebootId");
|
||||||
|
|
||||||
std::string const StaticStrings::New("new");
|
std::string const StaticStrings::New("new");
|
||||||
std::string const StaticStrings::Old("old");
|
std::string const StaticStrings::Old("old");
|
||||||
|
std::string const StaticStrings::UpgradeEnvName(
|
||||||
|
"ARANGODB_UPGRADE_DURING_RESTORE");
|
||||||
|
std::string const StaticStrings::BackupToDeleteName("DIRECTORY_TO_DELETE");
|
||||||
|
std::string const StaticStrings::BackupSearchToDeleteName("DIRECTORY_TO_DELETE_SEARCH");
|
||||||
|
|
|
@ -251,6 +251,9 @@ class StaticStrings {
|
||||||
static std::string const RebootId;
|
static std::string const RebootId;
|
||||||
static std::string const New;
|
static std::string const New;
|
||||||
static std::string const Old;
|
static std::string const Old;
|
||||||
|
static std::string const UpgradeEnvName;
|
||||||
|
static std::string const BackupToDeleteName;
|
||||||
|
static std::string const BackupSearchToDeleteName;
|
||||||
};
|
};
|
||||||
} // namespace arangodb
|
} // namespace arangodb
|
||||||
|
|
||||||
|
|
|
@ -217,6 +217,7 @@ public:
|
||||||
arangodb::RandomGenerator::initialize(arangodb::RandomGenerator::RandomType::MERSENNE);
|
arangodb::RandomGenerator::initialize(arangodb::RandomGenerator::RandomType::MERSENNE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_id = TRI_GetTempPath();
|
_id = TRI_GetTempPath();
|
||||||
_id += TRI_DIR_SEPARATOR_CHAR;
|
_id += TRI_DIR_SEPARATOR_CHAR;
|
||||||
_id += "arangotest-";
|
_id += "arangotest-";
|
||||||
|
@ -330,14 +331,16 @@ public:
|
||||||
pathname += "backups";
|
pathname += "backups";
|
||||||
pathname += TRI_DIR_SEPARATOR_CHAR;
|
pathname += TRI_DIR_SEPARATOR_CHAR;
|
||||||
pathname += _idRestore;
|
pathname += _idRestore;
|
||||||
|
pathname += TRI_DIR_SEPARATOR_CHAR;
|
||||||
|
pathname += "engine_rocksdb";
|
||||||
retVal = TRI_CreateRecursiveDirectory(pathname.c_str(), systemError,
|
retVal = TRI_CreateRecursiveDirectory(pathname.c_str(), systemError,
|
||||||
systemErrorStr);
|
systemErrorStr);
|
||||||
|
|
||||||
EXPECT_EQ(TRI_ERROR_NO_ERROR, retVal);
|
EXPECT_EQ(TRI_ERROR_NO_ERROR, retVal);
|
||||||
|
|
||||||
|
writeFile(pathname.c_str(), "../META", "{\"version\":\"" ARANGODB_VERSION "\", \"datetime\":\"xxx\", \"id\":\"xxx\"}");
|
||||||
writeFile(pathname.c_str(), "MANIFEST-000003", "manifest info");
|
writeFile(pathname.c_str(), "MANIFEST-000003", "manifest info");
|
||||||
writeFile(pathname.c_str(), "CURRENT", "MANIFEST-000003\n");
|
writeFile(pathname.c_str(), "CURRENT", "MANIFEST-000003\n");
|
||||||
writeFile(pathname.c_str(), "META", "{\"version\":\"" ARANGODB_VERSION "\", \"datetime\":\"xxx\", \"id\":\"xxx\"}");
|
|
||||||
writeFile(pathname.c_str(), "IDENTITY", "huh?");
|
writeFile(pathname.c_str(), "IDENTITY", "huh?");
|
||||||
writeFile(pathname.c_str(), "000111.sst", "raw data 1");
|
writeFile(pathname.c_str(), "000111.sst", "raw data 1");
|
||||||
writeFile(pathname.c_str(), "000111.sha.e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.hash", "");
|
writeFile(pathname.c_str(), "000111.sha.e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.hash", "");
|
||||||
|
@ -362,7 +365,7 @@ public:
|
||||||
|
|
||||||
/// @brief test
|
/// @brief test
|
||||||
TEST(RocksDBHotBackupRestoreDirectories, test_createRestoringDirectory) {
|
TEST(RocksDBHotBackupRestoreDirectories, test_createRestoringDirectory) {
|
||||||
std::string restoringDir, tempname;
|
std::string fullRestoringDir, restoringDir, restoringSearchDir, tempname;
|
||||||
bool retBool;
|
bool retBool;
|
||||||
|
|
||||||
VPackBuilder report;
|
VPackBuilder report;
|
||||||
|
@ -371,7 +374,7 @@ TEST(RocksDBHotBackupRestoreDirectories, test_createRestoringDirectory) {
|
||||||
RocksDBHotBackupRestoreTest testee(feature, VPackSlice(), report);
|
RocksDBHotBackupRestoreTest testee(feature, VPackSlice(), report);
|
||||||
testee.createHotDirectory();
|
testee.createHotDirectory();
|
||||||
|
|
||||||
retBool = testee.createRestoringDirectory(restoringDir);
|
retBool = testee.createRestoringDirectories(fullRestoringDir, restoringDir, restoringSearchDir);
|
||||||
|
|
||||||
// spot check files in restoring dir
|
// spot check files in restoring dir
|
||||||
EXPECT_TRUE( retBool );
|
EXPECT_TRUE( retBool );
|
||||||
|
@ -391,7 +394,8 @@ TEST(RocksDBHotBackupRestoreDirectories, test_createRestoringDirectory) {
|
||||||
EXPECT_TRUE( TRI_IsRegularFile(tempname.c_str()) ); // looks same as hard link
|
EXPECT_TRUE( TRI_IsRegularFile(tempname.c_str()) ); // looks same as hard link
|
||||||
|
|
||||||
// verify still present in originating dir
|
// verify still present in originating dir
|
||||||
restoringDir = testee.rebuildPath(testee.getDirectoryRestore());
|
restoringDir = testee.rebuildPath(testee.getDirectoryRestore() +
|
||||||
|
TRI_DIR_SEPARATOR_CHAR + "engine_rocksdb");
|
||||||
EXPECT_TRUE( TRI_ExistsFile(restoringDir.c_str()) );
|
EXPECT_TRUE( TRI_ExistsFile(restoringDir.c_str()) );
|
||||||
EXPECT_TRUE( TRI_IsDirectory(restoringDir.c_str()) );
|
EXPECT_TRUE( TRI_IsDirectory(restoringDir.c_str()) );
|
||||||
tempname = restoringDir + TRI_DIR_SEPARATOR_CHAR + "MANIFEST-000003";
|
tempname = restoringDir + TRI_DIR_SEPARATOR_CHAR + "MANIFEST-000003";
|
||||||
|
|
Loading…
Reference in New Issue