mirror of https://gitee.com/bigwinds/arangodb
parent
3b6e85f4a6
commit
956902a5a9
|
@ -1,6 +1,15 @@
|
|||
devel
|
||||
-----
|
||||
|
||||
* issue #3504: added option `--force-same-database` for arangorestore
|
||||
|
||||
with this option set to true, it is possible to make any arangorestore attempt
|
||||
fail if the specified target database does not match the database name
|
||||
specified in the source dump's "dump.json" file. it can thus be used to
|
||||
prevent restoring data into the "wrong" database
|
||||
|
||||
The option is set to `false` by default to ensure backwards-compatibility
|
||||
|
||||
* UI: updated dygraph js library to version 2.1.0
|
||||
|
||||
* added C++ implementation for AQL function `SHA512()`
|
||||
|
|
|
@ -41,6 +41,16 @@ target database, the username and passwords passed to _arangorestore_ (in option
|
|||
*--server.username* and *--server.password*) will be used to create an initial user for the
|
||||
new database.
|
||||
|
||||
The option `--force-same-database` allows restricting arangorestore operations to a
|
||||
database with the same name as in the source dump's "dump.json" file. It can thus be used
|
||||
to prevent restoring data into a "wrong" database by accident.
|
||||
|
||||
For example, if a dump was taken from database `a`, and the restore is attempted into
|
||||
database `b`, then with the `--force-same-database` option set to `true`, arangorestore
|
||||
will abort instantly.
|
||||
|
||||
The `--force-same-database` option is set to `false` by default to ensure backwards-compatibility.
|
||||
|
||||
Here's an example of reloading data to a non-standard endpoint, using a dedicated
|
||||
[database name](../Appendix/Glossary.md#database-name):
|
||||
|
||||
|
@ -120,16 +130,12 @@ intentional (normally, every server should create its own *_rev* values) there m
|
|||
situations when it is required to re-use the exact same *_rev* values for the reloaded data.
|
||||
This can be achieved by setting the *--recycle-ids* parameter to *true*:
|
||||
|
||||
unix> arangorestore --collection myusers --collection myvalues --recycle-ids true --input-directory "dump"
|
||||
unix> arangorestore --collection myusers --collection myvalues --input-directory "dump"
|
||||
|
||||
Note that setting *--recycle-ids* to *true* will also cause collections to be (re-)created in
|
||||
the target database with the exact same collection id as in the input directory. Any potentially
|
||||
existing collection in the target database with the same collection id will then be dropped.
|
||||
|
||||
Setting *--recycle-ids* to *false* or omitting it will only use the [collection name](../Appendix/Glossary.md#collection-name) from the
|
||||
input directory and allow the target database to create the collection with a different id
|
||||
(though with the same name) than in the input directory.
|
||||
|
||||
### Reloading Data into a different Collection
|
||||
|
||||
With some creativity you can use _arangodump_ and _arangorestore_ to transfer data from one
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "ApplicationFeatures/ApplicationServer.h"
|
||||
#include "Basics/FileUtils.h"
|
||||
#include "Basics/OpenFilesTracker.h"
|
||||
#include "Basics/Result.h"
|
||||
#include "Basics/StringUtils.h"
|
||||
#include "Basics/VelocyPackHelper.h"
|
||||
#include "Basics/files.h"
|
||||
|
@ -62,7 +63,7 @@ RestoreFeature::RestoreFeature(application_features::ApplicationServer* server,
|
|||
_chunkSize(1024 * 1024 * 8),
|
||||
_includeSystemCollections(false),
|
||||
_createDatabase(false),
|
||||
_inputDirectory(),
|
||||
_forceSameDatabase(false),
|
||||
_importData(true),
|
||||
_importStructure(true),
|
||||
_progress(true),
|
||||
|
@ -109,6 +110,10 @@ void RestoreFeature::collectOptions(
|
|||
options->addOption("--create-database",
|
||||
"create the target database if it does not exist",
|
||||
new BooleanParameter(&_createDatabase));
|
||||
|
||||
options->addOption("--force-same-database",
|
||||
"force usage of the same database name as in the source dump.json file",
|
||||
new BooleanParameter(&_forceSameDatabase));
|
||||
|
||||
options->addOption("--input-directory", "input directory",
|
||||
new StringParameter(&_inputDirectory));
|
||||
|
@ -385,7 +390,7 @@ static bool SortCollections(VPackBuilder const& l, VPackBuilder const& r) {
|
|||
return strcasecmp(leftName.c_str(), rightName.c_str()) < 0;
|
||||
}
|
||||
|
||||
int RestoreFeature::processInputDirectory(std::string& errorMsg) {
|
||||
Result RestoreFeature::readEncryptionInfo() {
|
||||
std::string encryptionType;
|
||||
try {
|
||||
std::string const encryptionFilename = FileUtils::buildFilename(_inputDirectory, "ENCRYPTION");
|
||||
|
@ -395,11 +400,9 @@ int RestoreFeature::processInputDirectory(std::string& errorMsg) {
|
|||
encryptionType = "none";
|
||||
}
|
||||
} catch (basics::Exception const& ex) {
|
||||
errorMsg = ex.what();
|
||||
return ex.code();
|
||||
return Result(ex.code(), ex.what());
|
||||
} catch (std::exception const& ex) {
|
||||
errorMsg = ex.what();
|
||||
return TRI_ERROR_INTERNAL;
|
||||
return Result(TRI_ERROR_INTERNAL, ex.what());
|
||||
} catch (...) {
|
||||
// file not found etc.
|
||||
}
|
||||
|
@ -415,6 +418,46 @@ int RestoreFeature::processInputDirectory(std::string& errorMsg) {
|
|||
#endif
|
||||
}
|
||||
|
||||
return Result();
|
||||
}
|
||||
|
||||
Result RestoreFeature::readDumpInfo() {
|
||||
std::string databaseName;
|
||||
|
||||
try {
|
||||
std::string const fqn = _inputDirectory + TRI_DIR_SEPARATOR_STR + "dump.json";
|
||||
#ifdef USE_ENTERPRISE
|
||||
VPackBuilder fileContentBuilder =
|
||||
(_encryption != nullptr)
|
||||
? _encryption->velocyPackFromFile(fqn)
|
||||
: basics::VelocyPackHelper::velocyPackFromFile(fqn);
|
||||
#else
|
||||
VPackBuilder fileContentBuilder =
|
||||
basics::VelocyPackHelper::velocyPackFromFile(fqn);
|
||||
#endif
|
||||
VPackSlice const fileContent = fileContentBuilder.slice();
|
||||
|
||||
databaseName = fileContent.get("database").copyString();
|
||||
} catch (...) {
|
||||
// the above may go wrong for several reasons
|
||||
}
|
||||
|
||||
if (!databaseName.empty()) {
|
||||
std::cout << "Database name in source dump is '" << databaseName << "'" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
ClientFeature* client =
|
||||
application_features::ApplicationServer::getFeature<ClientFeature>(
|
||||
"Client");
|
||||
if (_forceSameDatabase && databaseName != client->databaseName()) {
|
||||
return Result(TRI_ERROR_BAD_PARAMETER, std::string("database name in dump.json ('") + databaseName + "') does not match specified database name ('" + client->databaseName() + "')");
|
||||
}
|
||||
|
||||
return Result();
|
||||
}
|
||||
|
||||
int RestoreFeature::processInputDirectory(std::string& errorMsg) {
|
||||
// create a lookup table for collections
|
||||
std::map<std::string, bool> restrictList;
|
||||
for (size_t i = 0; i < _collections.size(); ++i) {
|
||||
|
@ -733,6 +776,26 @@ void RestoreFeature::start() {
|
|||
_httpClient->params().setUserNamePassword("/", client->username(),
|
||||
client->password());
|
||||
|
||||
// read encryption info
|
||||
{
|
||||
Result r = readEncryptionInfo();
|
||||
|
||||
if (r.fail()) {
|
||||
LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << r.errorMessage();
|
||||
FATAL_ERROR_EXIT();
|
||||
}
|
||||
}
|
||||
|
||||
// read dump info
|
||||
{
|
||||
Result r = readDumpInfo();
|
||||
|
||||
if (r.fail()) {
|
||||
LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << r.errorMessage();
|
||||
FATAL_ERROR_EXIT();
|
||||
}
|
||||
}
|
||||
|
||||
int err = TRI_ERROR_NO_ERROR;
|
||||
std::string versionString = _httpClient->getServerVersion(&err);
|
||||
|
||||
|
@ -793,9 +856,8 @@ void RestoreFeature::start() {
|
|||
<< _httpClient->getEndpointSpecification() << "'" << std::endl;
|
||||
}
|
||||
|
||||
std::string errorMsg = "";
|
||||
|
||||
int res;
|
||||
std::string errorMsg;
|
||||
try {
|
||||
res = processInputDirectory(errorMsg);
|
||||
} catch (std::exception const& ex) {
|
||||
|
|
|
@ -50,10 +50,11 @@ class RestoreFeature final : public application_features::ApplicationFeature,
|
|||
|
||||
private:
|
||||
std::vector<std::string> _collections;
|
||||
std::string _inputDirectory;
|
||||
uint64_t _chunkSize;
|
||||
bool _includeSystemCollections;
|
||||
bool _createDatabase;
|
||||
std::string _inputDirectory;
|
||||
bool _forceSameDatabase;
|
||||
bool _importData;
|
||||
bool _importStructure;
|
||||
bool _progress;
|
||||
|
@ -71,6 +72,8 @@ class RestoreFeature final : public application_features::ApplicationFeature,
|
|||
int sendRestoreIndexes(VPackSlice const& slice, std::string& errorMsg);
|
||||
int sendRestoreData(std::string const& cname, char const* buffer,
|
||||
size_t bufferSize, std::string& errorMsg);
|
||||
Result readEncryptionInfo();
|
||||
Result readDumpInfo();
|
||||
int processInputDirectory(std::string& errorMsg);
|
||||
ssize_t readData(int fd, char* data, size_t len);
|
||||
void beginDecryption(int fd);
|
||||
|
|
Loading…
Reference in New Issue