1
0
Fork 0

generate/validate keys

This commit is contained in:
Jan Steemann 2014-04-11 16:19:00 +02:00
parent 03a65c25ce
commit d0bcb02015
13 changed files with 430 additions and 17 deletions

View File

@ -113,6 +113,7 @@ add_executable(
SkipLists/skiplistIndex.cpp
Transaction/Collection.cpp
Transaction/Context.cpp
Transaction/Helper.cpp
Transaction/IdGenerator.cpp
Transaction/Manager.cpp
Transaction/Operations.cpp

View File

@ -79,6 +79,7 @@ bin_arangod_SOURCES = \
arangod/SkipLists/skiplistIndex.cpp \
arangod/Transaction/Collection.cpp \
arangod/Transaction/Context.cpp \
arangod/Transaction/Helper.cpp \
arangod/Transaction/IdGenerator.cpp \
arangod/Transaction/Manager.cpp \
arangod/Transaction/Operations.cpp \

View File

@ -26,8 +26,11 @@
////////////////////////////////////////////////////////////////////////////////
#include "Collection.h"
#include "VocBase/vocbase.h"
#include "BasicsC/logging.h"
#include "Utils/Exception.h"
#include "VocBase/key-generator.h"
#include "VocBase/server.h"
#include "VocBase/vocbase.h"
using namespace std;
using namespace triagens::transaction;
@ -64,6 +67,46 @@ Collection::~Collection () {
// --SECTION-- public methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief generate a new revision
////////////////////////////////////////////////////////////////////////////////
TRI_voc_tick_t Collection::generateRevision () {
return TRI_NewTickServer();
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create a new key
////////////////////////////////////////////////////////////////////////////////
string Collection::generateKey (TRI_voc_tick_t revision) {
// no key specified, now create one
TRI_key_generator_t* keyGenerator = static_cast<TRI_key_generator_t*>(primary()->_keyGenerator);
// create key using key generator
string key(keyGenerator->generateKey(keyGenerator, revision));
if (key.empty()) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_OUT_OF_KEYS);
}
return key;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief validate a key
////////////////////////////////////////////////////////////////////////////////
void Collection::validateKey (std::string const& key) {
TRI_key_generator_t* keyGenerator = static_cast<TRI_key_generator_t*>(primary()->_keyGenerator);
int res = keyGenerator->validateKey(keyGenerator, key);
if (res != TRI_ERROR_NO_ERROR) {
THROW_ARANGO_EXCEPTION(res);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief finalise usage of the collection
////////////////////////////////////////////////////////////////////////////////

View File

@ -30,6 +30,7 @@
#include "Basics/Common.h"
#include "VocBase/primary-collection.h"
#include "VocBase/vocbase.h"
namespace triagens {
namespace transaction {
@ -139,6 +140,24 @@ namespace triagens {
return _collection->_collection;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generate a new revision
////////////////////////////////////////////////////////////////////////////////
TRI_voc_tick_t generateRevision ();
////////////////////////////////////////////////////////////////////////////////
/// @brief create a new key
////////////////////////////////////////////////////////////////////////////////
std::string generateKey (TRI_voc_tick_t);
////////////////////////////////////////////////////////////////////////////////
/// @brief validate a key
////////////////////////////////////////////////////////////////////////////////
void validateKey (std::string const&);
////////////////////////////////////////////////////////////////////////////////
/// @brief finalise usage of the collection
////////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,103 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief static transaction helper functions
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2004-2013 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 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#include "Helper.h"
#include "Transaction/transactions.h"
#include "VocBase/vocbase.h"
using namespace std;
using namespace triagens::basics;
using namespace triagens::transaction;
////////////////////////////////////////////////////////////////////////////////
/// @brief append a document key
////////////////////////////////////////////////////////////////////////////////
bool Helper::appendKey (Bson& document,
string const& key) {
return document.appendUtf8(string(TRI_VOC_ATTRIBUTE_KEY), key);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief extract a document key
/// this will throw if the document key is invalid
/// if the document does not contain the _key attribute, an empty string will
/// be returned
////////////////////////////////////////////////////////////////////////////////
string Helper::documentKey (Bson const& document) {
BsonIter iter(document);
if (! iter.find(TRI_VOC_ATTRIBUTE_KEY)) {
// no _key attribute
return "";
}
// document has _key attribute
if (iter.getType() != BSON_TYPE_UTF8) {
// _key has an invalid type
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD);
}
// _key is a string
string const key = iter.getUtf8();
if (key.empty()) {
// _key is empty
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD);
}
return key;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a BSON document from the string
////////////////////////////////////////////////////////////////////////////////
Bson Helper::documentFromJson (string const& data) {
return documentFromJson(data.c_str(), data.size());
}
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a BSON document from the string
////////////////////////////////////////////////////////////////////////////////
Bson Helper::documentFromJson (char const* data,
size_t length) {
Bson document;
if (! document.fromJson(data)) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID);
}
return document;
}
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

View File

@ -0,0 +1,78 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief static transaction helper functions
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2004-2013 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 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#ifndef TRIAGENS_TRANSACTION_HELPER_H
#define TRIAGENS_TRANSACTION_HELPER_H 1
#include "Basics/Common.h"
#include "Basics/BsonHelper.h"
namespace triagens {
namespace transaction {
class Helper {
public:
////////////////////////////////////////////////////////////////////////////////
/// @brief append a document key
////////////////////////////////////////////////////////////////////////////////
static bool appendKey (basics::Bson&,
std::string const&);
////////////////////////////////////////////////////////////////////////////////
/// @brief extract a document key
/// this will throw if the document key is invalid
/// if the document does not contain the _key attribute, an empty string will
/// be returned
////////////////////////////////////////////////////////////////////////////////
static std::string documentKey (basics::Bson const&);
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a BSON document from the string
////////////////////////////////////////////////////////////////////////////////
static basics::Bson documentFromJson (std::string const&);
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a BSON document from the string
////////////////////////////////////////////////////////////////////////////////
static basics::Bson documentFromJson (char const*,
size_t);
};
}
}
#endif
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

View File

@ -63,9 +63,18 @@ namespace triagens {
return (char*) buffer + sizeof(TRI_df_marker_t);
}
template <typename T> void storeValue (char*& ptr, T value) {
inline void advance (char*& ptr, size_t length) {
ptr += length;
}
template <typename T> void store (char*& ptr, T value) {
*((T*) ptr) = value;
ptr += sizeof(T);
advance(ptr, sizeof(T));
}
void store (char*& ptr, char const* src, size_t length) {
memcpy(ptr, src, length);
advance(ptr, length);
}
char* buffer;
@ -75,14 +84,24 @@ namespace triagens {
struct DocumentMarker : public Marker {
DocumentMarker (TRI_voc_tick_t databaseId,
TRI_voc_cid_t collectionId,
std::string const& key,
TRI_voc_tick_t revision,
triagens::basics::Bson const& document)
: Marker(TRI_WAL_MARKER_DOCUMENT_STANDALONE, sizeof(TRI_voc_tick_t) + sizeof(TRI_voc_cid_t) + document.getSize()) {
: Marker(TRI_WAL_MARKER_DOCUMENT_STANDALONE,
sizeof(TRI_voc_tick_t) + sizeof(TRI_voc_cid_t) + sizeof(TRI_voc_tick_t) + key.size() + 2 + document.getSize()) {
char* p = data();
storeValue<TRI_voc_tick_t>(p, databaseId);
storeValue<TRI_voc_cid_t>(p, collectionId);
store<TRI_voc_tick_t>(p, databaseId);
store<TRI_voc_cid_t>(p, collectionId);
store<TRI_voc_tick_t>(p, revision);
memcpy(p, document.getBuffer(), document.getSize());
// store key
store<uint8_t>(p, (uint8_t) key.size());
store(p, key.c_str(), key.size());
store<unsigned char>(p, '\0');
// store bson
store(p, (char const*) document.getBuffer(), static_cast<size_t>(document.getSize()));
}
~DocumentMarker () {

View File

@ -29,6 +29,7 @@
#include "BasicsC/logging.h"
#include "Transaction/Collection.h"
#include "Transaction/Context.h"
#include "Transaction/Helper.h"
#include "Transaction/Marker.h"
#include "Transaction/Transaction.h"
#include "Utils/Exception.h"
@ -260,10 +261,22 @@ int WorkUnit::rollback () {
////////////////////////////////////////////////////////////////////////////////
int WorkUnit::saveDocument (Collection* collection,
triagens::basics::Bson const& document,
triagens::basics::Bson& document,
bool waitForSync) {
// generate a tick value
TRI_voc_tick_t revision = collection->generateRevision();
DocumentMarker marker(collection->databaseId(), collection->id(), document);
// validate or create key
string key(Helper::documentKey(document));
if (key.empty()) {
key = collection->generateKey(revision);
Helper::appendKey(document, key);
}
else {
collection->validateKey(key);
}
DocumentMarker marker(collection->databaseId(), collection->id(), key, revision, document);
LogfileManager* logfileManager = _context->logfileManager();

View File

@ -152,7 +152,7 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
int saveDocument (Collection*,
triagens::basics::Bson const&,
triagens::basics::Bson&,
bool);
// -----------------------------------------------------------------------------

View File

@ -31,6 +31,7 @@
#include "Basics/Common.h"
#include "BasicsC/logging.h"
#include "Transaction/Context.h"
#include "Transaction/Helper.h"
#include "Transaction/Manager.h"
#include "Transaction/Transaction.h"
#include "Transaction/WorkUnit.h"

View File

@ -32,6 +32,7 @@
#include "BasicsC/logging.h"
#include "BasicsC/tri-strings.h"
#include "BasicsC/voc-errors.h"
#include "Basics/StringUtils.h"
#include "VocBase/vocbase.h"
@ -221,6 +222,52 @@ static void TraditionalFree (TRI_key_generator_t* const generator) {
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create a new document key
////////////////////////////////////////////////////////////////////////////////
static std::string TraditionalGenerateKey (TRI_key_generator_t* const generator,
TRI_voc_tick_t revision) {
traditional_keygen_t* data = static_cast<traditional_keygen_t*>(generator->_data);
assert(data != 0);
// user has not specified a key, generate one based on tick
return triagens::basics::StringUtils::itoa(revision);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief validate a document key
////////////////////////////////////////////////////////////////////////////////
static int TraditionalValidateKey (TRI_key_generator_t* const generator,
std::string const& key) {
traditional_keygen_t* data = static_cast<traditional_keygen_t*>(generator->_data);
assert(data != 0);
// user has specified a key
if (! key.empty() && ! data->_allowUserKeys) {
// we do not allow user-generated keys
return TRI_ERROR_ARANGO_DOCUMENT_KEY_UNEXPECTED;
}
if (key.empty()) {
// user key is empty
return TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD;
}
if (key.size() > TRI_VOC_KEY_MAX_LENGTH) {
// user key is too long
return TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD;
}
// validate user-supplied key
if (! ValidateKey(key.c_str())) {
return TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD;
}
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generate a new key
/// the caller must make sure that the outBuffer is big enough to hold at least
@ -465,6 +512,67 @@ static uint64_t AutoIncrementNext (const uint64_t lastValue,
return next;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generate a new key
////////////////////////////////////////////////////////////////////////////////
static std::string AutoIncrementGenerateKey (TRI_key_generator_t* const generator,
TRI_voc_tick_t revision) {
autoincrement_keygen_t* data = static_cast<autoincrement_keygen_t*>(generator->_data);
assert(data != 0);
// user has not specified a key, generate one based on algorithm
uint64_t keyValue = AutoIncrementNext(data->_lastValue, data->_increment, data->_offset);
// bounds and sanity checks
if (keyValue == UINT64_MAX || keyValue < data->_lastValue) {
return "";
}
assert(keyValue > data->_lastValue);
// update our last value
data->_lastValue = keyValue;
return triagens::basics::StringUtils::itoa(keyValue);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief validate a key
////////////////////////////////////////////////////////////////////////////////
static int AutoIncrementValidateKey (TRI_key_generator_t* const generator,
std::string const& key) {
autoincrement_keygen_t* data = static_cast<autoincrement_keygen_t*>(generator->_data);
assert(data != 0);
if (! key.empty() && ! data->_allowUserKeys) {
// we do not allow user-generated keys
return TRI_ERROR_ARANGO_DOCUMENT_KEY_UNEXPECTED;
}
if (key.empty()) {
return TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD;
}
if (key.size() > TRI_VOC_KEY_MAX_LENGTH) {
// user key is too long
return TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD;
}
// validate user-supplied key
if (! ValidateNumericKey(key.c_str())) {
return TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD;
}
uint64_t intValue = triagens::basics::StringUtils::uint64(key);
if (intValue > data->_lastValue) {
// update our last value
data->_lastValue = intValue;
}
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generate a new key
/// the caller must make sure that the outBuffer is big enough to hold at least
@ -662,6 +770,8 @@ static TRI_key_generator_t* CreateGenerator (const TRI_json_t* const parameters)
if (type == TYPE_TRADITIONAL) {
generator->init = &TraditionalInit;
generator->generate = &TraditionalGenerate;
generator->generateKey = &TraditionalGenerateKey;
generator->validateKey = &TraditionalValidateKey;
generator->free = &TraditionalFree;
generator->track = NULL;
generator->toJson = &TraditionalToJson;
@ -669,6 +779,8 @@ static TRI_key_generator_t* CreateGenerator (const TRI_json_t* const parameters)
else if (type == TYPE_AUTOINCREMENT) {
generator->init = &AutoIncrementInit;
generator->generate = &AutoIncrementGenerate;
generator->generateKey = &AutoIncrementGenerateKey;
generator->validateKey = &AutoIncrementValidateKey;
generator->free = &AutoIncrementFree;
generator->track = &AutoIncrementTrack;
generator->toJson = &AutoIncrementToJson;

View File

@ -29,6 +29,7 @@
#define TRIAGENS_VOC_BASE_KEY_GENERATOR_H 1
#include "BasicsC/common.h"
#include "Basics/Common.h"
#include "VocBase/vocbase.h"
@ -79,6 +80,8 @@ typedef struct TRI_key_generator_s {
int (*init)(struct TRI_key_generator_s* const, const struct TRI_json_s* const);
int (*generate)(struct TRI_key_generator_s* const, const size_t, const TRI_voc_tick_t, const char* const, char* const, size_t* const, bool);
std::string (*generateKey)(struct TRI_key_generator_s* const, TRI_voc_tick_t);
int (*validateKey)(struct TRI_key_generator_s* const, std::string const&);
void (*track)(struct TRI_key_generator_s* const, const TRI_voc_key_t);
void (*free)(struct TRI_key_generator_s* const);
struct TRI_json_s* (*toJson)(const struct TRI_key_generator_s* const);

View File

@ -287,26 +287,46 @@ namespace triagens {
return true;
}
bool fromJson (char const* value,
size_t length) {
TRI_json_t* json = TRI_JsonString(TRI_UNKNOWN_MEM_ZONE, value);
if (json == 0) {
return false;
}
bool result = parseJson(json);
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
return result;
}
bool fromJson (string const& value) {
TRI_json_t* json = TRI_JsonString(TRI_UNKNOWN_MEM_ZONE, value.c_str());
if (json == 0) {
return false;
}
if (json == NULL) {
bool result = parseJson(json);
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
return result;
}
bool parseJson (TRI_json_t* json) {
if (json == 0) {
return false;
}
if (json->_type != TRI_JSON_ARRAY) {
// wrong type. must be document
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
return false;
}
clear();
processJsonPart(json);
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
return true;
return processJsonPart(json);
}
bool toJson (string& result) {
@ -353,7 +373,7 @@ namespace triagens {
return static_cast<size_t>(bson_count_keys(&_bson));
}
bool hasField (string key) {
bool hasField (string const& key) {
return bson_has_field(&_bson, key.c_str());
}
}; // class Bson