1
0
Fork 0

Merge branch 'master' of github.com:triAGENS/AvocadoDB

This commit is contained in:
Frank Celler 2012-03-29 11:12:03 +02:00
commit 3b36edfdcb
8 changed files with 515 additions and 26 deletions

50
Rest/JsonContainer.cpp Normal file
View File

@ -0,0 +1,50 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief JSON data container
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2004-2012 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 "Rest/JsonContainer.h"
namespace triagens {
namespace rest {
////////////////////////////////////////////////////////////////////////////////
/// @brief constructs a JSON data container
////////////////////////////////////////////////////////////////////////////////
JsonContainer::JsonContainer (TRI_json_t* data) : _data(data) {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief destroys a JSON container
////////////////////////////////////////////////////////////////////////////////
JsonContainer::~JsonContainer () {
if (_data) {
TRI_FreeJson(_data);
}
}
}
}

82
Rest/JsonContainer.h Normal file
View File

@ -0,0 +1,82 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief JSON data container
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2004-2012 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_FYN_REST_JSON_CONTAINER_H
#define TRIAGENS_FYN_REST_JSON_CONTAINER_H 1
#include "BasicsC/json.h"
// -----------------------------------------------------------------------------
// --SECTION-- class JsonContainer
// -----------------------------------------------------------------------------
namespace triagens {
namespace rest {
////////////////////////////////////////////////////////////////////////////////
/// @brief JSON container
////////////////////////////////////////////////////////////////////////////////
class JsonContainer {
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
public:
////////////////////////////////////////////////////////////////////////////////
/// @brief constructs a JSON data container
////////////////////////////////////////////////////////////////////////////////
JsonContainer (TRI_json_t* data);
////////////////////////////////////////////////////////////////////////////////
/// @brief destroys a JSON container
////////////////////////////////////////////////////////////////////////////////
~JsonContainer ();
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief the json data
////////////////////////////////////////////////////////////////////////////////
TRI_json_t* _data;
};
}
}
#endif
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
// End:

View File

@ -30,6 +30,7 @@
#include "Basics/StringUtils.h"
#include "BasicsC/string-buffer.h"
#include "Rest/HttpRequest.h"
#include "Rest/JsonContainer.h"
#include "VocBase/simple-collection.h"
#include "VocBase/vocbase.h"
@ -247,6 +248,9 @@ bool RestDocumentHandler::createDocument () {
if (json == 0) {
return false;
}
// auto-ptr that will free JSON data when scope is left
JsonContainer container(json);
// find and load collection given by name oder identifier
int res = useCollection(collection, create);
@ -274,7 +278,6 @@ bool RestDocumentHandler::createDocument () {
// release collection and free json
releaseCollection();
TRI_FreeJson(json);
// generate result
if (mptr._did != 0) {
@ -659,6 +662,9 @@ bool RestDocumentHandler::updateDocument () {
return false;
}
// auto-ptr that will free JSON data when scope is left
JsonContainer container(json);
// extract document identifier
TRI_voc_did_t did = StringUtils::uint64(didStr);
@ -695,7 +701,7 @@ bool RestDocumentHandler::updateDocument () {
// release collection
releaseCollection();
// generate result
if (mptr._did != 0) {
generateUpdated(cid, did, mptr._rid);

View File

@ -127,6 +127,9 @@ TRI_barrier_t* TRI_CreateBarrierDatafile (TRI_barrier_list_t* container,
TRI_barrier_datafile_cb_t* element;
element = TRI_Allocate(sizeof(TRI_barrier_datafile_cb_t));
if (!element) {
return NULL;
}
element->base._type = TRI_BARRIER_DATAFILE_CALLBACK;
element->base._container = container;
@ -172,6 +175,9 @@ TRI_barrier_t* TRI_CreateBarrierCollection (TRI_barrier_list_t* container,
TRI_barrier_collection_cb_t* element;
element = TRI_Allocate(sizeof(TRI_barrier_collection_cb_t));
if (!element) {
return NULL;
}
element->base._type = TRI_BARRIER_COLLECTION_CALLBACK;
element->base._container = container;

View File

@ -1677,6 +1677,22 @@ static bool InitSimCollection (TRI_sim_collection_t* collection,
TRI_shaper_t* shaper) {
TRI_index_t* primary;
char* id;
// create primary index
primary = TRI_Allocate(sizeof(TRI_index_t));
if (primary == NULL) {
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
return false;
}
id = TRI_DuplicateString("_id");
if (id == NULL) {
TRI_Free(primary);
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
return false;
}
TRI_InitDocCollection(&collection->base, shaper);
@ -1706,22 +1722,6 @@ static bool InitSimCollection (TRI_sim_collection_t* collection,
TRI_InitVectorPointer(&collection->_indexes);
// create primary index
primary = TRI_Allocate(sizeof(TRI_index_t));
if (primary == NULL) {
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
return false;
}
id = TRI_DuplicateString("_id");
if (id == NULL) {
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
TRI_Free(primary);
return false;
}
TRI_InitVectorString(&primary->_fields);
TRI_PushBackVectorString(&primary->_fields, id);
@ -1832,18 +1832,34 @@ TRI_sim_collection_t* TRI_CreateSimCollection (char const* path,
////////////////////////////////////////////////////////////////////////////////
void TRI_DestroySimCollection (TRI_sim_collection_t* collection) {
size_t i;
size_t n;
TRI_DestroyCondition(&collection->_journalsCondition);
TRI_DestroyAssociativePointer(&collection->_primaryIndex);
TRI_DestroyMultiPointer(&collection->_edgesIndex);
TRI_FreeSimpleHeaders(collection->_headers);
TRI_DestroyReadWriteLock(&collection->_lock);
// free memory allocated for index field names
n = collection->_indexes._length;
for (i = 0 ; i < n ; ++i) {
TRI_index_t* idx = (TRI_index_t*) collection->_indexes._buffer[i];
TRI_DestroyVectorString(&idx->_fields);
}
// free index vector
TRI_DestroyVectorPointer(&collection->_indexes);
if (collection->base._shaper != NULL) {
TRI_FreeVocShaper(collection->base._shaper);
}
/* FIXME: DestroyDocCollection does also free the shaper?? */
TRI_DestroyDocCollection(&collection->base);
}

View File

@ -288,9 +288,13 @@ static bool DropCollectionCallback (TRI_collection_t* col, void* data) {
break;
}
}
// we need to clean up the pointers later so we insert it into this vector
TRI_PushBackVectorPointer(&vocbase->_deadCollections, collection);
TRI_WRITE_UNLOCK_COLLECTIONS_VOCBASE(vocbase);
// .............................................................................
// rename collection directory
// .............................................................................
@ -363,6 +367,29 @@ static bool DropCollectionCallback (TRI_collection_t* col, void* data) {
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief free the path buffer allocated for a collection
////////////////////////////////////////////////////////////////////////////////
static inline void FreeCollectionPath (TRI_vocbase_col_t* const collection) {
if (collection->_path) {
TRI_Free((char*) collection->_path);
}
collection->_path = NULL;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief free the memory associated with a collection
////////////////////////////////////////////////////////////////////////////////
static void FreeCollection (TRI_vocbase_t* vocbase, TRI_vocbase_col_t* collection) {
FreeCollectionPath(collection);
TRI_DestroyReadWriteLock(&collection->_lock);
TRI_Free(collection);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief adds a new collection
////////////////////////////////////////////////////////////////////////////////
@ -386,9 +413,18 @@ static TRI_vocbase_col_t* AddCollection (TRI_vocbase_t* vocbase,
collection->_vocbase = vocbase;
collection->_type = type;
TRI_CopyString(collection->_name, name, sizeof(collection->_name));
collection->_path = (path == NULL ? NULL : TRI_DuplicateString(path));
/* FIXME: memory allocation might fail */
/* FIXME: collection->_path is never freed after being assigned to */
if (path == NULL) {
collection->_path = NULL;
}
else {
collection->_path = TRI_DuplicateString(path);
if (!collection->_path) {
TRI_Free(collection);
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
return NULL;
}
}
collection->_collection = NULL;
collection->_status = TRI_VOC_COL_STATUS_CORRUPTED;
@ -398,6 +434,7 @@ static TRI_vocbase_col_t* AddCollection (TRI_vocbase_t* vocbase,
found = TRI_InsertKeyAssociativePointer(&vocbase->_collectionsByName, name, collection, false);
if (found != NULL) {
FreeCollectionPath(collection);
TRI_Free(collection);
LOG_ERROR("duplicate entry for name '%s'", name);
@ -411,6 +448,7 @@ static TRI_vocbase_col_t* AddCollection (TRI_vocbase_t* vocbase,
if (found != NULL) {
TRI_RemoveKeyAssociativePointer(&vocbase->_collectionsByName, name);
FreeCollectionPath(collection);
TRI_Free(collection);
LOG_ERROR("duplicate collection identifier '%lu' for name '%s'", (unsigned long) cid, name);
@ -455,6 +493,10 @@ static int ScanPath (TRI_vocbase_t* vocbase, char const* path) {
}
file = TRI_Concatenate2File(path, name);
if (!file) {
LOG_FATAL("out of memory");
return TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
}
if (TRI_IsDirectory(file)) {
TRI_col_info_t info;
@ -478,6 +520,9 @@ static int ScanPath (TRI_vocbase_t* vocbase, char const* path) {
if (c == NULL) {
LOG_FATAL("failed to add simple document collection from '%s'", file);
TRI_FreeString(file);
regfree(&re);
TRI_DestroyVectorString(&files);
return TRI_set_errno(TRI_ERROR_AVOCADO_CORRUPTED_COLLECTION);
}
@ -623,6 +668,7 @@ static int ManifestCollectionVocBase (TRI_vocbase_t* vocbase, TRI_vocbase_col_t*
collection->_status = TRI_VOC_COL_STATUS_LOADED;
collection->_collection = &sim->base;
FreeCollectionPath(collection);
collection->_path = TRI_DuplicateString(sim->base.base._directory);
TRI_WRITE_UNLOCK_STATUS_VOCBASE_COL(collection);
@ -738,6 +784,7 @@ static int LoadCollectionVocBase (TRI_vocbase_t* vocbase, TRI_vocbase_col_t* col
collection->_collection = &sim->base;
collection->_status = TRI_VOC_COL_STATUS_LOADED;
FreeCollectionPath(collection);
collection->_path = TRI_DuplicateString(sim->base.base._directory);
// release the WRITE lock and try again
@ -963,6 +1010,7 @@ TRI_vocbase_t* TRI_OpenVocBase (char const* path) {
}
TRI_InitVectorPointer(&vocbase->_collections);
TRI_InitVectorPointer(&vocbase->_deadCollections);
TRI_InitAssociativePointer(&vocbase->_collectionsById,
HashKeyCid,
@ -988,6 +1036,7 @@ TRI_vocbase_t* TRI_OpenVocBase (char const* path) {
TRI_DestroyAssociativePointer(&vocbase->_collectionsByName);
TRI_DestroyAssociativePointer(&vocbase->_collectionsById);
TRI_DestroyVectorPointer(&vocbase->_collections);
TRI_DestroyVectorPointer(&vocbase->_deadCollections);
TRI_DestroyLockFile(vocbase->_lockFile);
TRI_FreeString(vocbase->_lockFile);
TRI_FreeShadowStore(vocbase->_cursors);
@ -1032,22 +1081,39 @@ void TRI_DestroyVocBase (TRI_vocbase_t* vocbase) {
// stop synchroniser and compactor
TRI_JoinThread(&vocbase->_synchroniser);
TRI_JoinThread(&vocbase->_compactor);
// free dead collections (already dropped but pointers still around)
for (i = 0; i < vocbase->_deadCollections._length; ++i) {
TRI_vocbase_col_t* collection;
collection = (TRI_vocbase_col_t*) vocbase->_deadCollections._buffer[i];
FreeCollection(vocbase, collection);
}
// clear the hashs and vectors
// free collections
for (i = 0; i < vocbase->_collections._length; ++i) {
TRI_vocbase_col_t* collection;
collection = (TRI_vocbase_col_t*) vocbase->_collections._buffer[i];
FreeCollection(vocbase, collection);
}
// clear the hashes and vectors
TRI_DestroyAssociativePointer(&vocbase->_collectionsByName);
TRI_DestroyAssociativePointer(&vocbase->_collectionsById);
TRI_DestroyVectorPointer(&vocbase->_collections);
TRI_DestroyVectorPointer(&vocbase->_deadCollections);
// free query functions
TRI_FreeQueryFunctions(vocbase->_functions);
// free the cursors
TRI_FreeShadowStore(vocbase->_cursors);
// release lock on database
TRI_DestroyLockFile(vocbase->_lockFile);
TRI_FreeString(vocbase->_lockFile);
// free the cursors
TRI_FreeShadowStore(vocbase->_cursors);
// destroy lock
TRI_DestroyReadWriteLock(&vocbase->_lock);
}
@ -1218,6 +1284,7 @@ TRI_vocbase_col_t* TRI_CreateCollectionVocBase (TRI_vocbase_t* vocbase, TRI_col_
collection->_status = TRI_VOC_COL_STATUS_LOADED;
collection->_collection = doc;
FreeCollectionPath(collection);
collection->_path = TRI_DuplicateString(doc->base._directory);
TRI_WRITE_UNLOCK_COLLECTIONS_VOCBASE(vocbase);

View File

@ -271,6 +271,7 @@ typedef struct TRI_vocbase_s {
TRI_read_write_lock_t _lock;
TRI_vector_pointer_t _collections;
TRI_vector_pointer_t _deadCollections; // pointers to collections dropped that can be removed later
TRI_associative_pointer_t _collectionsByName;
TRI_associative_pointer_t _collectionsById;

View File

@ -0,0 +1,261 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief querying and managing collections
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2012 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 Achim Brandt
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var actions = require("actions");
var API = "_api/database/";
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup AvocadoAPI
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @fn JSA_GET_api_datebase_collections
/// @brief returns all collections
///
/// @REST{GET /_api/database/collections}
///
/// Returns all collections. The result is a list of objects with the following
/// attributes:
///
/// @FA{id}
///
/// The identifier of the collection.
///
/// @FA{name}
///
/// The name of the collection.
///
/// @EXAMPLES
///
/// @verbinclude api_database1
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : API + "collections",
context : "api",
callback : function (req, res) {
if (req.requestType != actions.GET) {
actions.resultUnsupported(req, res);
}
else {
var collections = db._collections();
var result = [];
for (var i = 0; i < collections.length; ++i) {
collection = collections[i];
result.push({ id : collection._id, name : collection.name() });
}
actions.result(req, res, actions.HTTP_OK, result);
}
}
});
////////////////////////////////////////////////////////////////////////////////
/// @brief returns information about a collection
///
/// @REST{GET /_api/database/collection/@FA{collection-identifier}}
///
/// The result is an objects with the following attributes:
///
/// @FA{id}
///
/// The identifier of the collection.
///
/// @FA{name}
///
/// The name of the collection.
///
/// @EXAMPLES
///
/// Using a name:
///
/// @verbinclude api_database2
///
/// Using an identifier:
///
/// @verbinclude api_database3
////////////////////////////////////////////////////////////////////////////////
function GET_api_database_collection (req, res) {
if (req.suffix.length != 1) {
actions.collectionUnknown(req, res);
}
else {
var name = req.suffix[0];
var id = parseInt(name);
if (id != NaN) {
name = id;
}
var collection = db._collection(name);
if (collection == null) {
actions.collectionUnknown(req, res, name);
}
else {
var result = {};
result.id = collection._id;
result.name = collection.name();
actions.resultOk(req, res, actions.HTTP_OK, result);
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a new collection
///
/// @REST{POST /_api/database/collection}
///
/// Creates a new collection. If the collection could be create, a @LIT{HTTP 200}
/// is returned. If the collection already exists, a @LIT{HTTP 409} is
/// returned.
///
/// The call expects a JSON hash array as body with the following
/// attributes:
///
/// @FA{name}
///
/// The name of the collection.
///
/// @FA{waitForSync} (optional, default true)
///
/// If @FA{waitForSync} is false, then creation of documents will not wait
/// for the synchronization to file.
///
/// In case of success, returns information about the created collection:
///
/// @FA{id}
///
/// The identifier of the collection.
///
/// @FA{name}
///
/// The name of the collection.
///
/// @EXAMPLES
///
/// Create a collection named test:
///
/// @verbinclude api_database4
///
/// Try it again:
///
/// @verbinclude api_database5
////////////////////////////////////////////////////////////////////////////////
function POST_api_database_collection (req, res) {
var body = JSON.parse(req.requestBody || "{}");
var name = body.name;
var waitForSync = true;
if (body.hasOwnProperty("waitForSync")) {
waitForSync = body.waitForSync;
}
if (name == null) {
badParameter(req, res, "name");
}
else {
var collection = db._collection(name);
if (collection != null) {
actions.error(req, res,
actions.HTTP_CONFLICT,
actions.VERR_COLLECTION_EXISTS,
"collection already exists",
undefined,
{ name : collection.name(), id : collection._id });
}
else {
collection = db[name];
if (collection == null) {
actions.badParameter(req, res, "cannot create collection named '" + name + "'");
}
else {
if (collection._id == 0) {
collection.load();
}
if (collection._id == 0) {
actions.badParameter(req, res, "cannot create collection named '" + name + "'");
}
else {
var result = {};
result.id = collection._id;
result.name = collection.name();
collection.parameter({ waitForSync : waitForSync });
actions.resultOk(req, res, actions.HTTP_OK, result);
}
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief reads or creates a collection
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : API + "collection",
context : "api",
callback : function (req, res) {
if (req.requestType == actions.GET) {
GET_api_database_collection(req, res);
}
else if (req.requestType == actions.POST) {
POST_api_database_collection(req, res);
}
else {
actions.resultUnsupported(req, res);
}
}
});
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End: