1
0
Fork 0

Merge branch 'devel' of https://github.com/triAGENS/ArangoDB into devel

This commit is contained in:
a-brandt 2012-10-30 12:31:50 +01:00
commit 3fb488c3a3
13 changed files with 1694 additions and 156 deletions

View File

@ -439,7 +439,6 @@ bool RestDocumentHandler::readSingleDocument (bool generateBody) {
TRI_voc_cid_t cid = ca.cid();
TRI_shaper_t* shaper = ca.shaper();
//TRI_voc_did_t id = StringUtils::uint64(did);
// .............................................................................
// inside read transaction
@ -983,7 +982,6 @@ bool RestDocumentHandler::deleteDocument () {
string key = suffix[1];
// extract document identifier
//TRI_voc_did_t did = StringUtils::uint64(didStr);
// extract the revision
TRI_voc_rid_t revision = extractRevision("if-match", "rev");

View File

@ -58,7 +58,6 @@ v8::Handle<v8::Value> TRI_ObjectReference (TRI_voc_cid_t cid, TRI_voc_key_t key)
TRI_InitStringBuffer(&buffer, TRI_CORE_MEM_ZONE);
TRI_AppendUInt64StringBuffer(&buffer, cid);
TRI_AppendCharStringBuffer(&buffer, TRI_DOCUMENT_HANDLE_SEPARATOR_CHR);
//TRI_AppendUInt64StringBuffer(&buffer, did);
TRI_AppendStringStringBuffer(&buffer, (char*) key);
v8::Handle<v8::String> ref = v8::String::New(buffer._buffer);
@ -68,42 +67,6 @@ v8::Handle<v8::Value> TRI_ObjectReference (TRI_voc_cid_t cid, TRI_voc_key_t key)
return scope.Close(ref);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief extratcs identifiers from a object reference
////////////////////////////////////////////////////////////////////////////////
bool TRI_IdentifiersObjectReference (v8::Handle<v8::Value> value, TRI_voc_cid_t& cid, TRI_voc_did_t& did) {
bool error;
cid = 0;
did = 0;
if (value->IsNumber() || value->IsNumberObject()) {
did = (TRI_voc_did_t) TRI_ObjectToDouble(value, error);
return ! error;
}
string v = TRI_ObjectToString(value);
vector<string> doc = StringUtils::split(v, TRI_DOCUMENT_HANDLE_SEPARATOR_STR);
switch (doc.size()) {
case 1:
did = StringUtils::uint64(doc[1]);
return did != 0;
case 2:
cid = StringUtils::uint64(doc[0]);
did = StringUtils::uint64(doc[1]);
return cid != 0 && did != 0;
default:
return false;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

View File

@ -52,12 +52,6 @@
v8::Handle<v8::Value> TRI_ObjectReference (TRI_voc_cid_t, TRI_voc_key_t);
////////////////////////////////////////////////////////////////////////////////
/// @brief extratcs identifiers from a object reference
////////////////////////////////////////////////////////////////////////////////
bool TRI_IdentifiersObjectReference (v8::Handle<v8::Value>, TRI_voc_cid_t&, TRI_voc_did_t&);
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

View File

@ -260,33 +260,6 @@ static bool IsDocumentHandle (v8::Handle<v8::Value> arg, TRI_voc_cid_t& cid, TRI
TRI_v8_global_t* v8g;
v8g = (TRI_v8_global_t*) v8::Isolate::GetCurrent()->GetData();
/*
if (arg->IsNumber()) {
did = (TRI_voc_did_t) arg->ToNumber()->Value();
return true;
}
if (! arg->IsString()) {
return false;
}
TRI_Utf8ValueNFC str(TRI_UNKNOWN_MEM_ZONE, arg);
char const* s = *str;
if (s == 0) {
return false;
}
regmatch_t matches[3];
if (regexec(&v8g->DocumentIdRegex, s, sizeof(matches) / sizeof(matches[0]), matches, 0) == 0) {
cid = TRI_UInt64String2(s + matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so);
did = TRI_UInt64String2(s + matches[2].rm_so, matches[2].rm_eo - matches[2].rm_so);
return true;
}
return false;
*/
if (! arg->IsString()) {
return false;
@ -304,7 +277,6 @@ static bool IsDocumentHandle (v8::Handle<v8::Value> arg, TRI_voc_cid_t& cid, TRI
// "cid/key"
if (regexec(&v8g->DocumentIdRegex, s, sizeof(matches) / sizeof(matches[0]), matches, 0) == 0) {
cid = TRI_UInt64String2(s + matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so);
//did = TRI_UInt64String2(s + matches[2].rm_so, matches[2].rm_eo - matches[2].rm_so);
key = TRI_DuplicateString2Z(TRI_CORE_MEM_ZONE, s + matches[2].rm_so, matches[2].rm_eo - matches[2].rm_so);
return true;
}
@ -2598,6 +2570,41 @@ static v8::Handle<v8::Value> JS_ParseAhuacatl (v8::Arguments const& argv) {
static v8::Handle<v8::Value> JS_UpgradeVocbaseCol (v8::Arguments const& argv) {
v8::HandleScope scope;
// some typedefs for deprecated markers, only used inside this function
typedef uint64_t voc_did_t;
typedef struct {
TRI_df_marker_t base;
voc_did_t _did; // this is the tick for a create, but not an update
TRI_voc_rid_t _rid; // this is the tick for an create and update
TRI_voc_eid_t _sid;
TRI_shape_sid_t _shape;
}
doc_document_marker_t_deprecated;
typedef struct {
doc_document_marker_t_deprecated base;
TRI_voc_cid_t _toCid;
voc_did_t _toDid;
TRI_voc_cid_t _fromCid;
voc_did_t _fromDid;
}
doc_edge_marker_t_deprecated;
typedef struct {
TRI_df_marker_t base;
voc_did_t _did; // this is the tick for a create, but not an update
TRI_voc_rid_t _rid; // this is the tick for an create and update
TRI_voc_eid_t _sid;
}
doc_deletion_marker_t_deprecated;
if (argv.Length() != 0) {
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION, "usage: upgrade()")));
}
@ -2731,13 +2738,13 @@ static v8::Handle<v8::Value> JS_UpgradeVocbaseCol (v8::Arguments const& argv) {
switch (marker._type) {
case TRI_DOC_MARKER_DOCUMENT: {
TRI_doc_document_marker_t_deprecated* oldMarker = (TRI_doc_document_marker_t_deprecated*) &payload;
doc_document_marker_t_deprecated* oldMarker = (doc_document_marker_t_deprecated*) &payload;
TRI_doc_document_key_marker_t newMarker;
TRI_voc_size_t newMarkerSize = sizeof(TRI_doc_document_key_marker_t);
char* body = ((char*) oldMarker) + sizeof(TRI_doc_document_marker_t_deprecated);
TRI_voc_size_t bodySize = oldMarker->base._size - sizeof(TRI_doc_document_marker_t_deprecated);
TRI_voc_size_t bodySizePadded = paddedSize - sizeof(TRI_doc_document_marker_t_deprecated);
char* body = ((char*) oldMarker) + sizeof(doc_document_marker_t_deprecated);
TRI_voc_size_t bodySize = oldMarker->base._size - sizeof(doc_document_marker_t_deprecated);
TRI_voc_size_t bodySizePadded = paddedSize - sizeof(doc_document_marker_t_deprecated);
char* keyBody = 0;
TRI_voc_size_t keyBodySize = 0;
@ -2777,13 +2784,13 @@ static v8::Handle<v8::Value> JS_UpgradeVocbaseCol (v8::Arguments const& argv) {
}
case TRI_DOC_MARKER_EDGE: {
TRI_doc_edge_marker_t_deprecated* oldMarker = (TRI_doc_edge_marker_t_deprecated*) &payload;
doc_edge_marker_t_deprecated* oldMarker = (doc_edge_marker_t_deprecated*) &payload;
TRI_doc_edge_key_marker_t newMarker;
TRI_voc_size_t newMarkerSize = sizeof(TRI_doc_edge_key_marker_t);
char* body = ((char*) oldMarker) + sizeof(TRI_doc_edge_marker_t_deprecated);
TRI_voc_size_t bodySize = oldMarker->base.base._size - sizeof(TRI_doc_edge_marker_t_deprecated);
TRI_voc_size_t bodySizePadded = paddedSize - sizeof(TRI_doc_edge_marker_t_deprecated);
char* body = ((char*) oldMarker) + sizeof(doc_edge_marker_t_deprecated);
TRI_voc_size_t bodySize = oldMarker->base.base._size - sizeof(doc_edge_marker_t_deprecated);
TRI_voc_size_t bodySizePadded = paddedSize - sizeof(doc_edge_marker_t_deprecated);
char* keyBody = 0;
TRI_voc_size_t keyBodySize = 0;
@ -2844,7 +2851,7 @@ static v8::Handle<v8::Value> JS_UpgradeVocbaseCol (v8::Arguments const& argv) {
}
case TRI_DOC_MARKER_DELETION: {
TRI_doc_deletion_marker_t_deprecated* oldMarker = (TRI_doc_deletion_marker_t_deprecated*) &payload;
doc_deletion_marker_t_deprecated* oldMarker = (doc_deletion_marker_t_deprecated*) &payload;
TRI_doc_deletion_key_marker_t newMarker;
TRI_voc_size_t newMarkerSize = sizeof(TRI_doc_deletion_key_marker_t);

View File

@ -159,7 +159,7 @@ static void ReleaseSimpleHeaders (TRI_headers_t* h, TRI_doc_mptr_t* header) {
TRI_headers_t* TRI_CreateSimpleHeaders (size_t headerSize) {
simple_headers_t* headers = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(simple_headers_t), false);
if (!headers) {
if (headers == NULL) {
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
return NULL;
}

View File

@ -84,7 +84,8 @@ void TRI_FreeIndex (TRI_index_t* const idx) {
break;
case TRI_IDX_TYPE_PRIMARY_INDEX:
TRI_FreePrimaryIndex(idx);
TRI_DestroyPrimaryIndex(idx);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, idx);
break;
default:
@ -303,15 +304,6 @@ void TRI_DestroyPrimaryIndex (TRI_index_t* idx) {
TRI_DestroyVectorString(&idx->_fields);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief destroys a primary index and frees the pointer
////////////////////////////////////////////////////////////////////////////////
void TRI_FreePrimaryIndex (TRI_index_t* idx) {
TRI_DestroyPrimaryIndex(idx);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, idx);
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

View File

@ -318,12 +318,6 @@ bool TRI_NeedsFullCoverageIndex (const TRI_index_t* const);
void TRI_DestroyPrimaryIndex (TRI_index_t*);
////////////////////////////////////////////////////////////////////////////////
/// @brief destroys a primary index and frees the pointer
////////////////////////////////////////////////////////////////////////////////
void TRI_FreePrimaryIndex (TRI_index_t*);
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

View File

@ -111,7 +111,6 @@ TRI_doc_update_policy_e;
////////////////////////////////////////////////////////////////////////////////
typedef struct TRI_doc_mptr_s {
//TRI_voc_did_t _did; // this is the document identifier
TRI_voc_rid_t _rid; // this is the revision identifier
TRI_voc_eid_t _eid; // this is the step identifier
@ -224,12 +223,12 @@ TRI_doc_collection_info_t;
///
/// As before, but instead of a shaped json a json object must be given.
///
/// @FUN{TRI_voc_did_t createLock (TRI_primary_collection_t*, TRI_df_marker_type_e, TRI_shaped_json_t const*)}
/// @FUN{TRI_voc_key_t createLock (TRI_primary_collection_t*, TRI_df_marker_type_e, TRI_shaped_json_t const*)}
//////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// As before, but the function will acquire and release the write lock.
///
/// @FUN{TRI_doc_mptr_t const read (TRI_primary_collection_t*, TRI_voc_did_t)}
/// @FUN{TRI_doc_mptr_t const read (TRI_primary_collection_t*, TRI_voc_key_t)}
//////////////////////////////////////////////////////////////////////////
///
/// Returns the master pointer of the document with the given identifier. If the
@ -237,7 +236,7 @@ TRI_doc_collection_info_t;
/// the result is @LIT{0}. The function DOES NOT acquire or release a read
/// lock. This must be done by the caller.
///
/// @FUN{TRI_doc_mptr_t const update (TRI_primary_collection_t*, TRI_shaped_json_t const*, TRI_voc_did_t, TRI_voc_rid_t @FA{rid}, TRI_voc_rid_t* @FA{current}, TRI_doc_update_policy_e, bool @FA{release})}
/// @FUN{TRI_doc_mptr_t const update (TRI_primary_collection_t*, TRI_shaped_json_t const*, TRI_voc_key_t, TRI_voc_rid_t @FA{rid}, TRI_voc_rid_t* @FA{current}, TRI_doc_update_policy_e, bool @FA{release})}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// Updates an existing document of the collection and returns copy of a valid
@ -253,17 +252,17 @@ TRI_doc_collection_info_t;
/// performed if the current revision matches the given. In any case the current
/// revision after the updated of the document is returned in @FA{current}.
///
/// @FUN{TRI_doc_mptr_t const updateJson (TRI_primary_collection_t*, TRI_json_t const*, TRI_voc_did_t, TRI_voc_rid_t @FA{rid}, TRI_voc_rid_t* @FA{current}, TRI_doc_update_policy_e, bool @FA{release})}
/// @FUN{TRI_doc_mptr_t const updateJson (TRI_primary_collection_t*, TRI_json_t const*, TRI_voc_key_t, TRI_voc_rid_t @FA{rid}, TRI_voc_rid_t* @FA{current}, TRI_doc_update_policy_e, bool @FA{release})}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// As before, but instead of a shaped json a json object must be given.
///
/// @FUN{int updateLock (TRI_primary_collection_t*, TRI_shaped_json_t const*, TRI_voc_did_t, TRI_voc_rid_t @FA{rid}, TRI_voc_rid_t* @FA{current}, TRI_doc_update_policy_e)}
/// @FUN{int updateLock (TRI_primary_collection_t*, TRI_shaped_json_t const*, TRI_voc_key_t, TRI_voc_rid_t @FA{rid}, TRI_voc_rid_t* @FA{current}, TRI_doc_update_policy_e)}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// As before, but the function will acquire and release the write lock.
///
/// @FUN{int destroy (TRI_primary_collection_t*, TRI_voc_did_t, TRI_voc_rid_t, TRI_voc_rid_t @FA{rid}, TRI_voc_rid_t* @FA{current}, TRI_doc_update_policy_e, bool @FA{release})}
/// @FUN{int destroy (TRI_primary_collection_t*, TRI_voc_key_t, TRI_voc_rid_t, TRI_voc_rid_t @FA{rid}, TRI_voc_rid_t* @FA{current}, TRI_doc_update_policy_e, bool @FA{release})}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// Deletes an existing document from the given collection and returns @ref
@ -278,7 +277,7 @@ TRI_doc_collection_info_t;
/// valid revision of the document. If the delete was aborted, than @FA{current}
/// contains the revision of the still alive document.
///
/// @FUN{int destroyLock (TRI_primary_collection_t*, TRI_voc_did_t, TRI_voc_rid_t @FA{rid}, TRI_voc_rid_t* @FA{current}, TRI_doc_update_policy_e)}
/// @FUN{int destroyLock (TRI_primary_collection_t*, TRI_voc_key_t, TRI_voc_rid_t @FA{rid}, TRI_voc_rid_t* @FA{current}, TRI_doc_update_policy_e)}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// As before, but the function will acquire and release the write lock.
@ -334,36 +333,6 @@ typedef struct TRI_primary_collection_s {
}
TRI_primary_collection_t;
////////////////////////////////////////////////////////////////////////////////
/// @brief document datafile marker
////////////////////////////////////////////////////////////////////////////////
typedef struct TRI_doc_document_marker_s_deprecated {
TRI_df_marker_t base;
TRI_voc_did_t _did; // this is the tick for a create, but not an update
TRI_voc_rid_t _rid; // this is the tick for an create and update
TRI_voc_eid_t _sid;
TRI_shape_sid_t _shape;
}
TRI_doc_document_marker_t_deprecated;
////////////////////////////////////////////////////////////////////////////////
/// @brief edge datafile marker
////////////////////////////////////////////////////////////////////////////////
typedef struct TRI_doc_edge_marker_s_deprecated {
TRI_doc_document_marker_t_deprecated base;
TRI_voc_cid_t _toCid;
TRI_voc_did_t _toDid;
TRI_voc_cid_t _fromCid;
TRI_voc_did_t _fromDid;
}
TRI_doc_edge_marker_t_deprecated;
////////////////////////////////////////////////////////////////////////////////
/// @brief document datafile marker with key
////////////////////////////////////////////////////////////////////////////////
@ -401,19 +370,6 @@ TRI_doc_edge_key_marker_t;
/// @brief document datafile deletion marker
////////////////////////////////////////////////////////////////////////////////
typedef struct TRI_doc_deletion_marker_s_deprecated {
TRI_df_marker_t base;
TRI_voc_did_t _did; // this is the tick for a create, but not an update
TRI_voc_rid_t _rid; // this is the tick for an create and update
TRI_voc_eid_t _sid;
}
TRI_doc_deletion_marker_t_deprecated;
////////////////////////////////////////////////////////////////////////////////
/// @brief document datafile deletion marker
////////////////////////////////////////////////////////////////////////////////
typedef struct TRI_doc_deletion_key_marker_s {
TRI_df_marker_t base;

View File

@ -0,0 +1,419 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief primary index
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2011 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 "primary-index.h"
#include "BasicsC/hashes.h"
#define INITIAL_SIZE (128)
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief return the local id of the transaction that created a document
////////////////////////////////////////////////////////////////////////////////
static TRI_transaction_local_id_t DocumentTransaction (const TRI_transaction_doc_mptr_t* const doc) {
return doc->_validFrom;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check whether a specific transaction is currently running
////////////////////////////////////////////////////////////////////////////////
static bool InWriteTransactionsTable (const TRI_transaction_t* const trx,
const TRI_transaction_local_id_t id) {
return false;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief hashes the document key
////////////////////////////////////////////////////////////////////////////////
static uint64_t HashKey (const char* const key) {
return TRI_FnvHashString(key);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check constraints on previous documnent revision found
////////////////////////////////////////////////////////////////////////////////
static int CheckConstraint (TRI_revision_constraint_t* const constraint,
const TRI_transaction_doc_mptr_t* const doc) {
if (doc == NULL) {
// document not found
return TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND;
}
if (constraint != NULL) {
// return revision id found
constraint->_previousRevision = doc->_validFrom;
if (constraint->_policy == TRI_DOC_UPDATE_ERROR && constraint->_expectedRevision != doc->_validFrom) {
// revision ids do not match
return TRI_ERROR_ARANGO_CONFLICT;
}
else if (constraint->_policy == TRI_DOC_UPDATE_CONFLICT) {
return TRI_ERROR_NOT_IMPLEMENTED;
}
else if (constraint->_policy == TRI_DOC_UPDATE_ILLEGAL) {
return TRI_ERROR_INTERNAL;
}
}
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief compares a document key and a document
////////////////////////////////////////////////////////////////////////////////
static bool IsVisible (const TRI_transaction_t* const trx,
const char* const key,
const TRI_transaction_doc_mptr_t* const element) {
const TRI_transaction_local_id_t ownId = trx->_id._localId;
return (element->_validFrom < ownId) &&
(! InWriteTransactionsTable(trx, element->_validFrom)) &&
(element->_validTo == 0 || element->_validTo > ownId || InWriteTransactionsTable(trx, element->_validTo)) &&
(strcmp(key, element->_key) == 0);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief resizes the index
////////////////////////////////////////////////////////////////////////////////
static bool Resize (TRI_primary_index_t* const idx) {
TRI_transaction_doc_mptr_t** oldTable;
uint64_t oldAlloc;
uint64_t j;
oldTable = idx->_table;
oldAlloc = idx->_nrAlloc;
idx->_nrAlloc = 2 * idx->_nrAlloc + 1;
idx->_table = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, idx->_nrAlloc * sizeof(TRI_transaction_doc_mptr_t*), true);
if (idx->_table == NULL) {
// out of memory
idx->_nrAlloc = oldAlloc;
idx->_table = oldTable;
return false;
}
// reposition old elements into new index
for (j = 0; j < oldAlloc; ++j) {
if (oldTable[j] != NULL) {
const uint64_t hash = HashKey(oldTable[j]->_key);
uint64_t i;
i = hash % idx->_nrAlloc;
while (idx->_table[i] != NULL) {
i = (i + 1) % idx->_nrAlloc;
}
idx->_table[i] = oldTable[j];
}
}
TRI_Free(TRI_UNKNOWN_MEM_ZONE, oldTable);
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief looks up a document in the index
////////////////////////////////////////////////////////////////////////////////
static TRI_transaction_doc_mptr_t* Lookup (TRI_primary_index_t* const idx,
TRI_transaction_t* const trx,
const char* const key) {
const uint64_t hash = HashKey(key);
uint64_t i;
i = hash % idx->_nrAlloc;
// search the table
while (idx->_table[i] != NULL) {
if (IsVisible(trx, key, idx->_table[i])) {
return idx->_table[i];
}
i = (i + 1) % idx->_nrAlloc;
}
return NULL;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief insert a document into the index and return the previous revision
////////////////////////////////////////////////////////////////////////////////
static TRI_transaction_doc_mptr_t* Insert (TRI_primary_index_t* const idx,
TRI_transaction_t* const trx,
TRI_transaction_doc_mptr_t* const doc) {
const uint64_t hash = HashKey(doc->_key);
uint64_t i;
TRI_transaction_doc_mptr_t* old;
if (idx->_nrAlloc == idx->_nrUsed) {
return NULL;
}
i = hash % idx->_nrAlloc;
// search the table
while (idx->_table[i] != NULL && ! IsVisible(trx, doc->_key, idx->_table[i])) {
i = (i + 1) % idx->_nrAlloc;
}
// get previous element
old = idx->_table[i];
if (old != NULL) {
return old;
}
idx->_table[i] = doc;
idx->_nrUsed++;
// if we were adding and the table is more than half full, extend it
if (idx->_nrAlloc < 2 * idx->_nrUsed) {
Resize(idx);
}
return NULL;
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief create the primary index
////////////////////////////////////////////////////////////////////////////////
TRI_primary_index_t* TRI_CreatePrimaryIndex () {
TRI_primary_index_t* idx;
idx = (TRI_primary_index_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_primary_index_t), false);
if (idx == NULL) {
return NULL;
}
TRI_InitReadWriteLock(&idx->_lock);
idx->_table = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_transaction_doc_mptr_t*) * INITIAL_SIZE, true);
if (idx->_table == NULL) {
// out of memory
TRI_Free(TRI_UNKNOWN_MEM_ZONE, idx);
return NULL;
}
idx->_nrUsed = 0;
idx->_nrAlloc = INITIAL_SIZE;
return idx;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief free the primary index
////////////////////////////////////////////////////////////////////////////////
void TRI_FreePrimaryIndex (TRI_primary_index_t* const idx) {
assert(idx);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, &idx->_table);
TRI_DestroyReadWriteLock(&idx->_lock);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, idx);
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
TRI_transaction_doc_mptr_t* TRI_LookupPrimaryIndex (TRI_primary_index_t* const idx,
TRI_transaction_t* const trx,
const char* const key) {
TRI_transaction_doc_mptr_t* old;
// start critical section -----------------------------
TRI_ReadLockReadWriteLock(&idx->_lock);
old = Lookup(idx, trx, key);
// end critical section -----------------------------
TRI_ReadUnlockReadWriteLock(&idx->_lock);
return old;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief adds an element to the primary index
////////////////////////////////////////////////////////////////////////////////
int TRI_InsertPrimaryIndex (TRI_primary_index_t* const idx,
TRI_transaction_t* const trx,
TRI_transaction_doc_mptr_t* const doc) {
TRI_transaction_doc_mptr_t* old;
const TRI_transaction_local_id_t id = TRI_LocalIdTransaction(trx);
assert(id == DocumentTransaction(doc));
assert(doc->_validTo == 0);
assert(doc->_data != NULL);
// start critical section -----------------------------
TRI_WriteLockReadWriteLock(&idx->_lock);
old = Insert(idx, trx, doc);
if (old != NULL) {
// duplicate key error
TRI_WriteUnlockReadWriteLock(&idx->_lock);
return TRI_ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED;
}
// end critical section -----------------------------
TRI_WriteUnlockReadWriteLock(&idx->_lock);
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief updates an element in the primary index
////////////////////////////////////////////////////////////////////////////////
int TRI_UpdatePrimaryIndex (TRI_primary_index_t* const idx,
TRI_transaction_t* const trx,
TRI_transaction_doc_mptr_t* const doc,
TRI_revision_constraint_t* const constraint) {
TRI_transaction_doc_mptr_t* old;
const TRI_transaction_local_id_t id = TRI_LocalIdTransaction(trx);
int result;
assert(id == DocumentTransaction(doc));
assert(doc->_validTo == 0);
assert(doc->_data != NULL);
// start critical section -----------------------------
TRI_WriteLockReadWriteLock(&idx->_lock);
old = Lookup(idx, trx, doc->_key);
result = CheckConstraint(constraint, old);
if (result != TRI_ERROR_NO_ERROR) {
// an error occurred
// end critical section -----------------------------
TRI_WriteUnlockReadWriteLock(&idx->_lock);
return result;
}
// update previous revision
assert(old);
old->_validTo = id;
// end critical section -----------------------------
TRI_WriteUnlockReadWriteLock(&idx->_lock);
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief removes an element from the primary index
////////////////////////////////////////////////////////////////////////////////
int TRI_DeletePrimaryIndex (TRI_primary_index_t* const idx,
TRI_transaction_t* const trx,
TRI_transaction_doc_mptr_t* const doc,
TRI_revision_constraint_t* const constraint) {
TRI_transaction_doc_mptr_t* old;
const TRI_transaction_local_id_t id = TRI_LocalIdTransaction(trx);
int result;
assert(id == DocumentTransaction(doc));
assert(doc->_validTo == 0);
assert(doc->_data == NULL);
// start critical section -----------------------------
TRI_WriteLockReadWriteLock(&idx->_lock);
old = Lookup(idx, trx, doc->_key);
result = CheckConstraint(constraint, old);
if (result != TRI_ERROR_NO_ERROR) {
// an error occurred
// end critical section -----------------------------
TRI_WriteUnlockReadWriteLock(&idx->_lock);
return result;
}
// update previous revision
assert(old);
old->_validTo = id;
// end critical section -----------------------------
TRI_WriteUnlockReadWriteLock(&idx->_lock);
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
// End:

View File

@ -0,0 +1,129 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief primary index of a collection
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2011 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
////////////////////////////////////////////////////////////////////////////////
#ifndef TRIAGENS_DURHAM_VOC_BASE_PRIMARY_INDEX_H
#define TRIAGENS_DURHAM_VOC_BASE_PRIMARY_INDEX_H 1
#include "BasicsC/common.h"
#include "VocBase/primary-collection.h"
#include "VocBase/transaction.h"
#include "VocBase/vocbase.h"
#ifdef __cplusplus
extern "C" {
#endif
// -----------------------------------------------------------------------------
// --SECTION-- PRIMARY INDEX
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- public types
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief constraint container
////////////////////////////////////////////////////////////////////////////////
typedef struct TRI_revision_constraint_s {
TRI_doc_update_policy_e _policy;
TRI_transaction_local_id_t _expectedRevision;
TRI_transaction_local_id_t _previousRevision;
}
TRI_revision_constraint_t;
////////////////////////////////////////////////////////////////////////////////
/// @brief transactional master pointer
////////////////////////////////////////////////////////////////////////////////
typedef struct TRI_transaction_doc_mptr_s {
TRI_transaction_local_id_t _validFrom; // valid from trx id
TRI_transaction_local_id_t _validTo; // valid to trx id
char* _key; // document identifier (string)
TRI_voc_fid_t _fid; // datafile identifier
void const* _data; // pointer to the raw marker (NULL for deleted documents)
}
TRI_transaction_doc_mptr_t;
////////////////////////////////////////////////////////////////////////////////
/// @brief primary index of a collection
////////////////////////////////////////////////////////////////////////////////
typedef struct TRI_primary_index_s {
TRI_read_write_lock_t _lock;
TRI_transaction_doc_mptr_t** _table;
uint64_t _nrAlloc;
uint64_t _nrUsed;
}
TRI_primary_index_t;
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief create the primary index
////////////////////////////////////////////////////////////////////////////////
TRI_primary_index_t* TRI_CreatePrimaryIndex (void);
////////////////////////////////////////////////////////////////////////////////
/// @brief free the primary index
////////////////////////////////////////////////////////////////////////////////
void TRI_FreePrimaryIndex (TRI_primary_index_t* const);
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
#ifdef __cplusplus
}
#endif
#endif
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
// End:

View File

@ -0,0 +1,736 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief transaction subsystem
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2011 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 "transaction.h"
#include "BasicsC/logging.h"
#include "BasicsC/strings.h"
// -----------------------------------------------------------------------------
// --SECTION-- TRANSACTION CONTEXT
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief return the type of the transaction as a string
////////////////////////////////////////////////////////////////////////////////
static const char* TypeString (const TRI_transaction_type_e type) {
switch (type) {
case TRI_TRANSACTION_READ:
return "read";
case TRI_TRANSACTION_WRITE:
return "write";
}
assert(false);
return "unknown";
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return the status of the transaction as a string
////////////////////////////////////////////////////////////////////////////////
static const char* StatusString (const TRI_transaction_status_e status) {
switch (status) {
case TRI_TRANSACTION_CREATED:
return "created";
case TRI_TRANSACTION_RUNNING:
return "running";
case TRI_TRANSACTION_COMMITTED:
return "committed";
case TRI_TRANSACTION_ABORTED:
return "aborted";
case TRI_TRANSACTION_FINISHED:
return "finished";
}
assert(false);
return "unknown";
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generate a transaction id
/// The context lock must be held when calling this function
////////////////////////////////////////////////////////////////////////////////
static TRI_transaction_local_id_t NextLocalTransactionId (TRI_transaction_context_t* const context) {
TRI_transaction_local_id_t id;
id = ++context->_id._localId;
return (TRI_transaction_local_id_t) id;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief register a transaction in the global transactions list
/// The context lock must be held when calling this function
////////////////////////////////////////////////////////////////////////////////
static int InsertTransactionList (TRI_transaction_list_t* const list,
TRI_transaction_t* const trx) {
const TRI_transaction_local_id_t id = trx->_id._localId;
int res;
TRI_transaction_list_entry_t entry;
assert(trx->_status == TRI_TRANSACTION_RUNNING);
entry._id = id;
entry._status = TRI_TRANSACTION_RUNNING;
res = TRI_PushBackVector(&list->_vector, &entry);
if (res == TRI_ERROR_NO_ERROR) {
++list->_numRunning;
}
return res;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief locate a transaction in the global transactions list using a
/// binary search
/// The context lock must be held when calling this function
////////////////////////////////////////////////////////////////////////////////
static TRI_transaction_list_entry_t* FindTransactionList (const TRI_transaction_list_t* const list,
const TRI_transaction_local_id_t id,
size_t* position) {
TRI_transaction_list_entry_t* entry;
size_t l, r, n;
LOG_TRACE("looking up transaction %lu", (unsigned long) id);
n = list->_vector._length;
if (n == 0) {
return NULL;
}
l = 0;
r = n - 1;
while (true) {
const size_t i = l + ((r - l) / 2);
if (r < l) {
// transaction not found
return NULL;
}
entry = (TRI_transaction_list_entry_t*) TRI_AtVector(&list->_vector, i);
assert(entry);
if (entry->_id == id) {
// found the transaction
*position = i;
return entry;
}
if (entry->_id > id) {
r = i - 1;
}
else {
l = i + 1;
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief remove a transaction from the global transactions list
/// The context lock must be held when calling this function
////////////////////////////////////////////////////////////////////////////////
static int RemoveTransactionList (TRI_transaction_list_t* const list,
const TRI_transaction_local_id_t id) {
TRI_transaction_list_entry_t* entry;
size_t position;
entry = FindTransactionList(list, id, &position);
if (entry == NULL) {
// transaction not found, should not happen
LOG_ERROR("logical error in transaction list");
return TRI_ERROR_INTERNAL;
}
assert(entry);
// update counters
if (entry->_status == TRI_TRANSACTION_RUNNING) {
--list->_numRunning;
}
else {
LOG_ERROR("logical error in transaction list");
assert(false);
}
// remove it from the vector
TRI_RemoveVector(&list->_vector, position);
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief remove a transaction from the global transactions list
/// The context lock must be held when calling this function
////////////////////////////////////////////////////////////////////////////////
static int UpdateTransactionList (TRI_transaction_list_t* const list,
const TRI_transaction_local_id_t id,
const TRI_transaction_status_e status) {
TRI_transaction_list_entry_t* entry;
size_t position;
assert(status == TRI_TRANSACTION_ABORTED);
entry = FindTransactionList(list, id, &position);
if (entry == NULL) {
// transaction not found, should not happen
LOG_ERROR("logical error in transaction list");
return TRI_ERROR_INTERNAL;
}
// update counters
if (entry->_status == TRI_TRANSACTION_RUNNING) {
--list->_numRunning;
}
else {
LOG_ERROR("logical error in transaction list");
}
if (status == TRI_TRANSACTION_ABORTED) {
++list->_numAborted;
}
entry->_status = status;
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief initialise a transactions list
////////////////////////////////////////////////////////////////////////////////
static void InitTransactionList (TRI_transaction_list_t* const list) {
TRI_InitVector(&list->_vector, TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_transaction_list_entry_t));
list->_numRunning = 0;
list->_numAborted = 0;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief destroy a transactions list
////////////////////////////////////////////////////////////////////////////////
static void DestroyTransactionList (TRI_transaction_list_t* const list) {
TRI_DestroyVector(&list->_vector);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief dump the contents of a transaction list
////////////////////////////////////////////////////////////////////////////////
static void DumpTransactionList (const TRI_transaction_list_t* const list) {
size_t i, n;
n = list->_vector._length;
for (i = 0; i < n; ++i) {
TRI_transaction_list_entry_t* entry = TRI_AtVector(&list->_vector, i);
LOG_INFO("- trx: #%lu, status: %s",
(unsigned long) entry->_id,
StatusString(entry->_status));
}
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief create the global transaction context
////////////////////////////////////////////////////////////////////////////////
TRI_transaction_context_t* TRI_CreateTransactionContext (TRI_transaction_server_id_t serverId) {
TRI_transaction_context_t* context;
context = (TRI_transaction_context_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_transaction_context_t), false);
if (context == NULL) {
return context;
}
TRI_InitMutex(&context->_lock);
InitTransactionList(&context->_readTransactions);
InitTransactionList(&context->_writeTransactions);
context->_id._localId = 0;
context->_id._serverId = serverId;
return context;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief free the global transaction context
////////////////////////////////////////////////////////////////////////////////
void TRI_FreeTransactionContext (TRI_transaction_context_t* const context) {
DestroyTransactionList(&context->_writeTransactions);
DestroyTransactionList(&context->_readTransactions);
TRI_DestroyMutex(&context->_lock);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, context);
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief dump transaction context data
////////////////////////////////////////////////////////////////////////////////
void TRI_DumpTransactionContext (TRI_transaction_context_t* const context) {
TRI_LockMutex(&context->_lock);
LOG_INFO("transaction context, last-id: %lu:%lu",
(unsigned long) context->_id._serverId,
(unsigned long) context->_id._localId);
LOG_INFO("read transactions: numRunning: %lu, length: %lu, aborted: %lu",
(unsigned long) context->_readTransactions._vector._length,
(unsigned long) context->_readTransactions._numRunning,
(unsigned long) context->_readTransactions._numAborted);
DumpTransactionList(&context->_readTransactions);
LOG_INFO("write transactions: numRunning: %lu, length: %lu, aborted: %lu",
(unsigned long) context->_writeTransactions._vector._length,
(unsigned long) context->_writeTransactions._numRunning,
(unsigned long) context->_writeTransactions._numAborted);
DumpTransactionList(&context->_writeTransactions);
TRI_UnlockMutex(&context->_lock);
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- TRANSACTION
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief create a transaction collection container
////////////////////////////////////////////////////////////////////////////////
static TRI_transaction_collection_t* CreateCollection (const char* const name,
const TRI_transaction_type_e type) {
TRI_transaction_collection_t* collection;
collection = (TRI_transaction_collection_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_transaction_collection_t), false);
if (collection == NULL) {
return NULL;
}
collection->_name = TRI_DuplicateStringZ(TRI_UNKNOWN_MEM_ZONE, name);
if (collection->_name == NULL) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, collection);
return NULL;
}
collection->_type = type;
return collection;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief free a transaction collection container
////////////////////////////////////////////////////////////////////////////////
static void FreeCollection (TRI_transaction_collection_t* collection) {
assert(collection);
assert(collection->_name);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, collection);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief register a transaction
////////////////////////////////////////////////////////////////////////////////
static int RegisterTransaction (TRI_transaction_t* const trx) {
TRI_transaction_context_t* context;
TRI_transaction_list_t* list;
int res;
assert(trx->_status == TRI_TRANSACTION_CREATED);
assert(trx->_collections._length > 0);
context = trx->_context;
trx->_status = TRI_TRANSACTION_RUNNING;
if (trx->_type == TRI_TRANSACTION_READ) {
// read-only transaction
list = &context->_readTransactions;
}
else {
list = &context->_writeTransactions;
}
// start critical section -----------------------------------------
TRI_LockMutex(&context->_lock);
trx->_id._localId = NextLocalTransactionId(context);
res = InsertTransactionList(list, trx);
TRI_UnlockMutex(&context->_lock);
// end critical section -----------------------------------------
return res;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief update the status of a transaction
////////////////////////////////////////////////////////////////////////////////
static int UpdateTransactionStatus (TRI_transaction_t* const trx,
const TRI_transaction_status_e status) {
const TRI_transaction_local_id_t id = trx->_id._localId;
TRI_transaction_context_t* context;
int res;
assert(trx->_status == TRI_TRANSACTION_RUNNING);
context = trx->_context;
// start critical section -----------------------------------------
TRI_LockMutex(&context->_lock);
if (trx->_type == TRI_TRANSACTION_READ) {
// read-only transactions cannot commit or roll-back
assert(status == TRI_TRANSACTION_FINISHED);
LOG_TRACE("removing read transaction %lu", (unsigned long) id);
res = RemoveTransactionList(&context->_readTransactions, id);
}
else {
// write transactions
if (status == TRI_TRANSACTION_COMMITTED) {
LOG_TRACE("removing write transaction %lu", (unsigned long) id);
res = RemoveTransactionList(&context->_writeTransactions, id);
}
else if (status == TRI_TRANSACTION_ABORTED) {
LOG_TRACE("updating write transaction %lu status %s", (unsigned long) id, StatusString(status));
res = UpdateTransactionList(&context->_writeTransactions, id, status);
}
else {
res = TRI_ERROR_INTERNAL;
}
}
TRI_UnlockMutex(&context->_lock);
// end critical section -----------------------------------------
if (res == TRI_ERROR_NO_ERROR) {
trx->_status = status;
}
return res;
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief create a new transaction container
////////////////////////////////////////////////////////////////////////////////
TRI_transaction_t* TRI_CreateTransaction (TRI_transaction_context_t* const context,
const TRI_transaction_isolation_level_e isolationLevel) {
TRI_transaction_t* trx;
trx = (TRI_transaction_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_transaction_t), false);
if (trx == NULL) {
// out of memory
return NULL;
}
trx->_context = context;
trx->_id._serverId = context->_id._serverId;
trx->_id._localId = 0;
trx->_status = TRI_TRANSACTION_CREATED;
trx->_type = TRI_TRANSACTION_READ;
trx->_isolationLevel = isolationLevel;
TRI_InitVectorPointer(&trx->_collections, TRI_UNKNOWN_MEM_ZONE);
return trx;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief free a transaction container
////////////////////////////////////////////////////////////////////////////////
void TRI_FreeTransaction (TRI_transaction_t* const trx) {
size_t i;
assert(trx);
if (trx->_status == TRI_TRANSACTION_RUNNING) {
TRI_AbortTransaction(trx);
}
// free all collections
i = trx->_collections._length;
while (i-- > 0) {
TRI_transaction_collection_t* collection = TRI_AtVectorPointer(&trx->_collections, i);
FreeCollection(collection);
if (i == 0) {
break;
}
}
TRI_DestroyVectorPointer(&trx->_collections);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, trx);
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief return the local id of a transaction
////////////////////////////////////////////////////////////////////////////////
TRI_transaction_local_id_t TRI_LocalIdTransaction (const TRI_transaction_t* const trx) {
return trx->_id._localId;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief dump information about a transaction
////////////////////////////////////////////////////////////////////////////////
void TRI_DumpTransaction (TRI_transaction_t* const trx) {
size_t i, n;
LOG_INFO("transaction id: %lu:%lu, type: %s, status: %s",
(unsigned long) trx->_id._serverId,
(unsigned long) trx->_id._localId,
TypeString(trx->_type),
StatusString(trx->_status));
n = trx->_collections._length;
for (i = 0; i < n; ++i) {
TRI_transaction_collection_t* collection = TRI_AtVectorPointer(&trx->_collections, i);
LOG_INFO("- collection: %s, type: %s", collection->_name, TypeString(collection->_type));
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief add a collection to a transaction
////////////////////////////////////////////////////////////////////////////////
bool TRI_AddCollectionTransaction (TRI_transaction_t* const trx,
const char* const name,
const TRI_transaction_type_e type) {
TRI_transaction_collection_t* collection;
size_t i, n;
assert(trx->_status == TRI_TRANSACTION_CREATED);
assert(name);
// upgrade transaction type if required
if (type == TRI_TRANSACTION_WRITE && trx->_type == TRI_TRANSACTION_READ) {
trx->_type = TRI_TRANSACTION_WRITE;
}
// check if we already have got this collection in the vector
n = trx->_collections._length;
for (i = 0; i < n; ++i) {
int res;
collection = TRI_AtVectorPointer(&trx->_collections, i);
res = strcmp(name, collection->_name);
if (res < 0) {
collection = CreateCollection(name, type);
if (collection == NULL) {
// out of memory
return false;
}
TRI_InsertVectorPointer(&trx->_collections, collection, i);
return true;
}
if (res == 0) {
// collection is already contained in vector
// upgrade collection type if required
if (type == TRI_TRANSACTION_WRITE && collection->_type == TRI_TRANSACTION_READ) {
collection->_type = TRI_TRANSACTION_WRITE;
}
return true;
}
}
// collection was not contained. now insert it
collection = CreateCollection(name, type);
if (collection == NULL) {
// out of memory
return false;
}
TRI_PushBackVectorPointer(&trx->_collections, collection);
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief start a transaction
////////////////////////////////////////////////////////////////////////////////
int TRI_StartTransaction (TRI_transaction_t* const trx) {
int res;
assert(trx->_status == TRI_TRANSACTION_CREATED);
res = RegisterTransaction(trx);
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
trx->_status = TRI_TRANSACTION_RUNNING;
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief commit a transaction
////////////////////////////////////////////////////////////////////////////////
int TRI_CommitTransaction (TRI_transaction_t* const trx) {
assert(trx->_status == TRI_TRANSACTION_RUNNING);
return UpdateTransactionStatus(trx, TRI_TRANSACTION_COMMITTED);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief abort a transaction
////////////////////////////////////////////////////////////////////////////////
int TRI_AbortTransaction (TRI_transaction_t* const trx) {
assert(trx->_status == TRI_TRANSACTION_RUNNING);
return UpdateTransactionStatus(trx, TRI_TRANSACTION_ABORTED);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief finish a transaction
////////////////////////////////////////////////////////////////////////////////
int TRI_FinishTransaction (TRI_transaction_t* const trx) {
assert(trx->_status == TRI_TRANSACTION_RUNNING);
if (trx->_type == TRI_TRANSACTION_READ) {
// read transactions
return UpdateTransactionStatus(trx, TRI_TRANSACTION_FINISHED);
}
else {
// write transactions
return UpdateTransactionStatus(trx, TRI_TRANSACTION_COMMITTED);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
// End:

View File

@ -0,0 +1,356 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief transaction subsystem
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2011 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
////////////////////////////////////////////////////////////////////////////////
#ifndef TRIAGENS_DURHAM_VOC_BASE_TRANSACTION_H
#define TRIAGENS_DURHAM_VOC_BASE_TRANSACTION_H 1
#include "BasicsC/common.h"
#include "BasicsC/locks.h"
#include "BasicsC/vector.h"
#include "BasicsC/voc-errors.h"
#ifdef __cplusplus
extern "C" {
#endif
// -----------------------------------------------------------------------------
// --SECTION-- TRANSACTION TYPES
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- public types
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief local transaction id typedef
////////////////////////////////////////////////////////////////////////////////
typedef uint64_t TRI_transaction_local_id_t;
////////////////////////////////////////////////////////////////////////////////
/// @brief server identifier type
////////////////////////////////////////////////////////////////////////////////
typedef uint16_t TRI_transaction_server_id_t;
////////////////////////////////////////////////////////////////////////////////
/// @brief transaction id typedef
////////////////////////////////////////////////////////////////////////////////
typedef struct TRI_transaction_id_s {
TRI_transaction_local_id_t _localId;
TRI_transaction_server_id_t _serverId;
}
TRI_transaction_id_t;
////////////////////////////////////////////////////////////////////////////////
/// @brief transaction isolation level
////////////////////////////////////////////////////////////////////////////////
typedef enum {
TRI_TRANSACTION_READ_UNCOMMITED = 1,
TRI_TRANSACTION_READ_COMMITTED = 2,
TRI_TRANSACTION_READ_REPEATABLE = 3
}
TRI_transaction_isolation_level_e;
////////////////////////////////////////////////////////////////////////////////
/// @brief transaction type
////////////////////////////////////////////////////////////////////////////////
typedef enum {
TRI_TRANSACTION_READ = 1,
TRI_TRANSACTION_WRITE = 2
}
TRI_transaction_type_e;
////////////////////////////////////////////////////////////////////////////////
/// @brief transaction statuses
////////////////////////////////////////////////////////////////////////////////
typedef enum {
TRI_TRANSACTION_CREATED = 0,
TRI_TRANSACTION_RUNNING = 1,
TRI_TRANSACTION_COMMITTED = 2,
TRI_TRANSACTION_ABORTED = 3,
TRI_TRANSACTION_FINISHED = 4
}
TRI_transaction_status_e;
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- TRANSACTION LIST
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- public types
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief an entry in the transactions list
////////////////////////////////////////////////////////////////////////////////
typedef struct TRI_transaction_list_entry_s {
TRI_transaction_local_id_t _id;
TRI_transaction_status_e _status;
}
TRI_transaction_list_entry_t;
////////////////////////////////////////////////////////////////////////////////
/// @brief transaction list typedef
////////////////////////////////////////////////////////////////////////////////
typedef struct TRI_transaction_list_s {
TRI_vector_t _vector; // vector containing trx_list_entry_t
size_t _numRunning; // number of currently running trx
size_t _numAborted; // number of already aborted trx
}
TRI_transaction_list_t;
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- TRANSACTION CONTEXT
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- public types
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief transaction context typedef
////////////////////////////////////////////////////////////////////////////////
typedef struct TRI_transaction_context_s {
TRI_transaction_id_t _id;
TRI_mutex_t _lock;
TRI_transaction_list_t _readTransactions;
TRI_transaction_list_t _writeTransactions;
}
TRI_transaction_context_t;
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief create the global transaction context
////////////////////////////////////////////////////////////////////////////////
TRI_transaction_context_t* TRI_CreateTransactionContext (TRI_transaction_server_id_t);
////////////////////////////////////////////////////////////////////////////////
/// @brief free the global transaction context
////////////////////////////////////////////////////////////////////////////////
void TRI_FreeTransactionContext (TRI_transaction_context_t*);
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
void TRI_DumpTransactionContext (TRI_transaction_context_t* const);
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- TRANSACTION
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- public types
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief collection used in a transaction
////////////////////////////////////////////////////////////////////////////////
typedef struct TRI_transaction_collection_s {
const char* _name;
TRI_transaction_type_e _type;
// locks and pointers go here
}
TRI_transaction_collection_t;
////////////////////////////////////////////////////////////////////////////////
/// @brief transaction typedef
////////////////////////////////////////////////////////////////////////////////
typedef struct TRI_transaction_s {
TRI_transaction_context_t* _context;
TRI_transaction_id_t _id;
TRI_transaction_type_e _type;
TRI_transaction_status_e _status;
TRI_transaction_isolation_level_e _isolationLevel;
TRI_vector_pointer_t _collections;
}
TRI_transaction_t;
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief create a new transaction container
////////////////////////////////////////////////////////////////////////////////
TRI_transaction_t* TRI_CreateTransaction (TRI_transaction_context_t* const,
const TRI_transaction_isolation_level_e);
////////////////////////////////////////////////////////////////////////////////
/// @brief free a transaction container
////////////////////////////////////////////////////////////////////////////////
void TRI_FreeTransaction (TRI_transaction_t* const);
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief return the local id of a transaction
////////////////////////////////////////////////////////////////////////////////
TRI_transaction_local_id_t TRI_LocalIdTransaction (const TRI_transaction_t* const);
////////////////////////////////////////////////////////////////////////////////
/// @brief dump information about a transaction
////////////////////////////////////////////////////////////////////////////////
void TRI_DumpTransaction (TRI_transaction_t* const);
////////////////////////////////////////////////////////////////////////////////
/// @brief add a collection to a transaction
////////////////////////////////////////////////////////////////////////////////
bool TRI_AddCollectionTransaction (TRI_transaction_t* const,
const char* const,
const TRI_transaction_type_e);
////////////////////////////////////////////////////////////////////////////////
/// @brief start a transaction
////////////////////////////////////////////////////////////////////////////////
int TRI_StartTransaction (TRI_transaction_t* const);
////////////////////////////////////////////////////////////////////////////////
/// @brief commit a transaction
////////////////////////////////////////////////////////////////////////////////
int TRI_CommitTransaction (TRI_transaction_t* const);
////////////////////////////////////////////////////////////////////////////////
/// @brief abort a transaction
////////////////////////////////////////////////////////////////////////////////
int TRI_AbortTransaction (TRI_transaction_t* const);
////////////////////////////////////////////////////////////////////////////////
/// @brief finish a transaction
////////////////////////////////////////////////////////////////////////////////
int TRI_FinishTransaction (TRI_transaction_t* const);
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
#ifdef __cplusplus
}
#endif
#endif
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
// End:

View File

@ -277,12 +277,6 @@ typedef uint64_t TRI_voc_cid_t;
typedef uint64_t TRI_voc_fid_t;
////////////////////////////////////////////////////////////////////////////////
/// @brief document identifier type
////////////////////////////////////////////////////////////////////////////////
typedef uint64_t TRI_voc_did_t;
////////////////////////////////////////////////////////////////////////////////
/// @brief document key identifier type
////////////////////////////////////////////////////////////////////////////////