From 21735bb26774ca12e9aa6ab8d69820c27823ce46 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Mon, 29 Oct 2012 15:34:28 +0100 Subject: [PATCH 1/4] minor changes --- arangod/VocBase/headers.c | 2 +- arangod/VocBase/index.c | 12 ++---------- arangod/VocBase/index.h | 6 ------ arangod/VocBase/primary-collection.h | 1 - 4 files changed, 3 insertions(+), 18 deletions(-) diff --git a/arangod/VocBase/headers.c b/arangod/VocBase/headers.c index 41b44ce2f3..a3f6da6664 100644 --- a/arangod/VocBase/headers.c +++ b/arangod/VocBase/headers.c @@ -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; } diff --git a/arangod/VocBase/index.c b/arangod/VocBase/index.c index 1a18df1011..cae2f067cf 100644 --- a/arangod/VocBase/index.c +++ b/arangod/VocBase/index.c @@ -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); -} - //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/VocBase/index.h b/arangod/VocBase/index.h index 07e742adf4..ca0fd4218d 100644 --- a/arangod/VocBase/index.h +++ b/arangod/VocBase/index.h @@ -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*); - //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/VocBase/primary-collection.h b/arangod/VocBase/primary-collection.h index 50a0c0ab93..c8e9100188 100644 --- a/arangod/VocBase/primary-collection.h +++ b/arangod/VocBase/primary-collection.h @@ -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 From b9008cbdd597fa81b03725afff3f01e0ac74f05d Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Mon, 29 Oct 2012 15:45:52 +0100 Subject: [PATCH 2/4] removed TRI_voc_did_t, removed some deprecated typedefs --- arangod/RestHandler/RestDocumentHandler.cpp | 2 - arangod/V8Server/v8-objects.cpp | 37 ---------- arangod/V8Server/v8-objects.h | 6 -- arangod/V8Server/v8-vocbase.cpp | 81 +++++++++++---------- arangod/VocBase/primary-collection.h | 57 ++------------- arangod/VocBase/vocbase.h | 6 -- 6 files changed, 51 insertions(+), 138 deletions(-) diff --git a/arangod/RestHandler/RestDocumentHandler.cpp b/arangod/RestHandler/RestDocumentHandler.cpp index a8464c91c3..4d19bce9d9 100644 --- a/arangod/RestHandler/RestDocumentHandler.cpp +++ b/arangod/RestHandler/RestDocumentHandler.cpp @@ -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"); diff --git a/arangod/V8Server/v8-objects.cpp b/arangod/V8Server/v8-objects.cpp index f06b5f26d2..22139b2b77 100644 --- a/arangod/V8Server/v8-objects.cpp +++ b/arangod/V8Server/v8-objects.cpp @@ -58,7 +58,6 @@ v8::Handle 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 ref = v8::String::New(buffer._buffer); @@ -68,42 +67,6 @@ v8::Handle 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 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 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; -} - //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/V8Server/v8-objects.h b/arangod/V8Server/v8-objects.h index 6145345714..72ef6c1714 100644 --- a/arangod/V8Server/v8-objects.h +++ b/arangod/V8Server/v8-objects.h @@ -52,12 +52,6 @@ v8::Handle TRI_ObjectReference (TRI_voc_cid_t, TRI_voc_key_t); -//////////////////////////////////////////////////////////////////////////////// -/// @brief extratcs identifiers from a object reference -//////////////////////////////////////////////////////////////////////////////// - -bool TRI_IdentifiersObjectReference (v8::Handle, TRI_voc_cid_t&, TRI_voc_did_t&); - //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/V8Server/v8-vocbase.cpp b/arangod/V8Server/v8-vocbase.cpp index 2e5541ae55..28c67914be 100755 --- a/arangod/V8Server/v8-vocbase.cpp +++ b/arangod/V8Server/v8-vocbase.cpp @@ -260,33 +260,6 @@ static bool IsDocumentHandle (v8::Handle 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 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 JS_ParseAhuacatl (v8::Arguments const& argv) { static v8::Handle 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 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 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 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); diff --git a/arangod/VocBase/primary-collection.h b/arangod/VocBase/primary-collection.h index c8e9100188..0d44ae8632 100644 --- a/arangod/VocBase/primary-collection.h +++ b/arangod/VocBase/primary-collection.h @@ -223,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 @@ -236,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 @@ -252,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 @@ -277,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. @@ -333,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 //////////////////////////////////////////////////////////////////////////////// @@ -400,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; diff --git a/arangod/VocBase/vocbase.h b/arangod/VocBase/vocbase.h index 9eb347bedb..5a3133d2c1 100644 --- a/arangod/VocBase/vocbase.h +++ b/arangod/VocBase/vocbase.h @@ -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 //////////////////////////////////////////////////////////////////////////////// From 665a6d4b7a82d89a3430ff285615a2a29afd9039 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Mon, 29 Oct 2012 18:14:42 +0100 Subject: [PATCH 3/4] transaction functionality, very early, not at all working --- arangod/VocBase/primary-index.c | 419 ++++++++++++++++++++++++++++++++ arangod/VocBase/primary-index.h | 129 ++++++++++ arangod/VocBase/transaction.c | 402 ++++++++++++++++++++++++++++++ arangod/VocBase/transaction.h | 277 +++++++++++++++++++++ 4 files changed, 1227 insertions(+) create mode 100644 arangod/VocBase/primary-index.c create mode 100644 arangod/VocBase/primary-index.h create mode 100644 arangod/VocBase/transaction.c create mode 100644 arangod/VocBase/transaction.h diff --git a/arangod/VocBase/primary-index.c b/arangod/VocBase/primary-index.c new file mode 100644 index 0000000000..24094b7f65 --- /dev/null +++ b/arangod/VocBase/primary-index.c @@ -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: diff --git a/arangod/VocBase/primary-index.h b/arangod/VocBase/primary-index.h new file mode 100644 index 0000000000..8c84d6dc90 --- /dev/null +++ b/arangod/VocBase/primary-index.h @@ -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: diff --git a/arangod/VocBase/transaction.c b/arangod/VocBase/transaction.c new file mode 100644 index 0000000000..15446c1176 --- /dev/null +++ b/arangod/VocBase/transaction.c @@ -0,0 +1,402 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @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-- constructors / destructors +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup VocBase +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief generate a transaction id +//////////////////////////////////////////////////////////////////////////////// + +static TRI_transaction_local_id_t NextLocalTransactionId (TRI_transaction_context_t* const context) { + TRI_transaction_local_id_t id; + + TRI_LockSpin(&context->_idLock); + id = ++context->_id._localId; + TRI_UnlockSpin(&context->_idLock); + + return (TRI_transaction_local_id_t) id; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +// ----------------------------------------------------------------------------- +// --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_InitSpin(&context->_idLock); + 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) { + TRI_DestroySpin(&context->_idLock); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, context); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +// ----------------------------------------------------------------------------- +// --SECTION-- TRANSACTION +// ----------------------------------------------------------------------------- + +// ----------------------------------------------------------------------------- +// --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_NONE: + return "none"; + case TRI_TRANSACTION_INITIALISED: + return "initialised"; + case TRI_TRANSACTION_RUNNING: + return "running"; + case TRI_TRANSACTION_COMMITTED: + return "committed"; + case TRI_TRANSACTION_ABORTED: + return "aborted"; + } + + assert(false); + return "unknown"; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @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); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +// ----------------------------------------------------------------------------- +// --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 = NextLocalTransactionId(context); + trx->_status = TRI_TRANSACTION_NONE; + 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_NONE); + 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) { + assert(trx->_status == TRI_TRANSACTION_NONE); + + trx->_status = TRI_TRANSACTION_INITIALISED; + 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 TRI_ERROR_NO_ERROR; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief abort a transaction +//////////////////////////////////////////////////////////////////////////////// + +int TRI_AbortTransaction (TRI_transaction_t* const trx) { + assert(trx->_status == TRI_TRANSACTION_INITIALISED || + trx->_status == TRI_TRANSACTION_RUNNING); + + return TRI_ERROR_NO_ERROR; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +// Local Variables: +// mode: outline-minor +// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)" +// End: diff --git a/arangod/VocBase/transaction.h b/arangod/VocBase/transaction.h new file mode 100644 index 0000000000..d3b237d14b --- /dev/null +++ b/arangod/VocBase/transaction.h @@ -0,0 +1,277 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @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 CONTEXT +// ----------------------------------------------------------------------------- + +// ----------------------------------------------------------------------------- +// --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 context typedef +//////////////////////////////////////////////////////////////////////////////// + +typedef struct TRI_transaction_context_s { + TRI_transaction_id_t _id; + TRI_spin_t _idLock; +} +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-- TRANSACTION +// ----------------------------------------------------------------------------- + +// ----------------------------------------------------------------------------- +// --SECTION-- public types +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup VocBase +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @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_NONE = 0, + TRI_TRANSACTION_INITIALISED = 1, + TRI_TRANSACTION_RUNNING = 2, + TRI_TRANSACTION_COMMITTED = 3, + TRI_TRANSACTION_ABORTED = 4 +} +TRI_transaction_status_e; + +//////////////////////////////////////////////////////////////////////////////// +/// @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); + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __cplusplus +} +#endif + +#endif + +// Local Variables: +// mode: outline-minor +// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)" +// End: From a585b64f79d41a00136bc5c81d86591cd31eb7e2 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Tue, 30 Oct 2012 11:17:54 +0100 Subject: [PATCH 4/4] implementation of global transaction lists --- arangod/VocBase/transaction.c | 506 ++++++++++++++++++++++++++++------ arangod/VocBase/transaction.h | 153 +++++++--- 2 files changed, 536 insertions(+), 123 deletions(-) diff --git a/arangod/VocBase/transaction.c b/arangod/VocBase/transaction.c index 15446c1176..bc4e498de7 100644 --- a/arangod/VocBase/transaction.c +++ b/arangod/VocBase/transaction.c @@ -34,78 +34,6 @@ // --SECTION-- TRANSACTION CONTEXT // ----------------------------------------------------------------------------- -// ----------------------------------------------------------------------------- -// --SECTION-- constructors / destructors -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup VocBase -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief generate a transaction id -//////////////////////////////////////////////////////////////////////////////// - -static TRI_transaction_local_id_t NextLocalTransactionId (TRI_transaction_context_t* const context) { - TRI_transaction_local_id_t id; - - TRI_LockSpin(&context->_idLock); - id = ++context->_id._localId; - TRI_UnlockSpin(&context->_idLock); - - return (TRI_transaction_local_id_t) id; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --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_InitSpin(&context->_idLock); - 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) { - TRI_DestroySpin(&context->_idLock); - TRI_Free(TRI_UNKNOWN_MEM_ZONE, context); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- TRANSACTION -// ----------------------------------------------------------------------------- - // ----------------------------------------------------------------------------- // --SECTION-- private functions // ----------------------------------------------------------------------------- @@ -137,22 +65,321 @@ static const char* TypeString (const TRI_transaction_type_e type) { static const char* StatusString (const TRI_transaction_status_e status) { switch (status) { - case TRI_TRANSACTION_NONE: - return "none"; - case TRI_TRANSACTION_INITIALISED: - return "initialised"; + 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 //////////////////////////////////////////////////////////////////////////////// @@ -189,6 +416,92 @@ static void FreeCollection (TRI_transaction_collection_t* collection) { 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; +} + //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// @@ -218,8 +531,8 @@ TRI_transaction_t* TRI_CreateTransaction (TRI_transaction_context_t* const conte trx->_context = context; trx->_id._serverId = context->_id._serverId; - trx->_id._localId = NextLocalTransactionId(context); - trx->_status = TRI_TRANSACTION_NONE; + trx->_id._localId = 0; + trx->_status = TRI_TRANSACTION_CREATED; trx->_type = TRI_TRANSACTION_READ; trx->_isolationLevel = isolationLevel; @@ -309,7 +622,7 @@ bool TRI_AddCollectionTransaction (TRI_transaction_t* const trx, TRI_transaction_collection_t* collection; size_t i, n; - assert(trx->_status == TRI_TRANSACTION_NONE); + assert(trx->_status == TRI_TRANSACTION_CREATED); assert(name); // upgrade transaction type if required @@ -363,9 +676,14 @@ bool TRI_AddCollectionTransaction (TRI_transaction_t* const trx, //////////////////////////////////////////////////////////////////////////////// int TRI_StartTransaction (TRI_transaction_t* const trx) { - assert(trx->_status == TRI_TRANSACTION_NONE); + int res; + assert(trx->_status == TRI_TRANSACTION_CREATED); + + res = RegisterTransaction(trx); + if (res != TRI_ERROR_NO_ERROR) { + return res; + } - trx->_status = TRI_TRANSACTION_INITIALISED; trx->_status = TRI_TRANSACTION_RUNNING; return TRI_ERROR_NO_ERROR; @@ -377,8 +695,8 @@ int TRI_StartTransaction (TRI_transaction_t* const trx) { int TRI_CommitTransaction (TRI_transaction_t* const trx) { assert(trx->_status == TRI_TRANSACTION_RUNNING); - - return TRI_ERROR_NO_ERROR; + + return UpdateTransactionStatus(trx, TRI_TRANSACTION_COMMITTED); } //////////////////////////////////////////////////////////////////////////////// @@ -386,10 +704,26 @@ int TRI_CommitTransaction (TRI_transaction_t* const trx) { //////////////////////////////////////////////////////////////////////////////// int TRI_AbortTransaction (TRI_transaction_t* const trx) { - assert(trx->_status == TRI_TRANSACTION_INITIALISED || - trx->_status == TRI_TRANSACTION_RUNNING); + assert(trx->_status == TRI_TRANSACTION_RUNNING); - return TRI_ERROR_NO_ERROR; + 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); + } } //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/VocBase/transaction.h b/arangod/VocBase/transaction.h index d3b237d14b..5141b8f0db 100644 --- a/arangod/VocBase/transaction.h +++ b/arangod/VocBase/transaction.h @@ -38,7 +38,7 @@ extern "C" { #endif // ----------------------------------------------------------------------------- -// --SECTION-- TRANSACTION CONTEXT +// --SECTION-- TRANSACTION TYPES // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- @@ -72,13 +72,105 @@ typedef struct TRI_transaction_id_s { } 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_spin_t _idLock; + TRI_transaction_id_t _id; + TRI_mutex_t _lock; + TRI_transaction_list_t _readTransactions; + TRI_transaction_list_t _writeTransactions; } TRI_transaction_context_t; @@ -111,6 +203,21 @@ void TRI_FreeTransactionContext (TRI_transaction_context_t*); /// @} //////////////////////////////////////////////////////////////////////////////// +// ----------------------------------------------------------------------------- +// --SECTION-- public functions +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup VocBase +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +void TRI_DumpTransactionContext (TRI_transaction_context_t* const); + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + // ----------------------------------------------------------------------------- // --SECTION-- TRANSACTION // ----------------------------------------------------------------------------- @@ -124,40 +231,6 @@ void TRI_FreeTransactionContext (TRI_transaction_context_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_NONE = 0, - TRI_TRANSACTION_INITIALISED = 1, - TRI_TRANSACTION_RUNNING = 2, - TRI_TRANSACTION_COMMITTED = 3, - TRI_TRANSACTION_ABORTED = 4 -} -TRI_transaction_status_e; - //////////////////////////////////////////////////////////////////////////////// /// @brief collection used in a transaction //////////////////////////////////////////////////////////////////////////////// @@ -261,6 +334,12 @@ int TRI_CommitTransaction (TRI_transaction_t* const); int TRI_AbortTransaction (TRI_transaction_t* const); +//////////////////////////////////////////////////////////////////////////////// +/// @brief finish a transaction +//////////////////////////////////////////////////////////////////////////////// + +int TRI_FinishTransaction (TRI_transaction_t* const); + //////////////////////////////////////////////////////////////////////////////// /// @} ////////////////////////////////////////////////////////////////////////////////