1
0
Fork 0

geo indexes

This commit is contained in:
Jan Steemann 2014-02-10 15:53:33 +01:00
parent 88bfe8f18c
commit 0479fd652f
2 changed files with 313 additions and 48 deletions

View File

@ -2660,30 +2660,222 @@ static v8::Handle<v8::Value> CreateVocBase (v8::Arguments const& argv,
return scope.Close(result);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief index comparator, used by the coordinator to detect if two index
/// contents are the same
////////////////////////////////////////////////////////////////////////////////
#ifdef TRI_ENABLE_CLUSTER
static bool CompareGeoIndex1Coordinator (TRI_json_t const* lhs,
TRI_json_t const* rhs) {
if (! TRI_CheckSameValueJson(TRI_LookupArrayJson(lhs, "unique"),
TRI_LookupArrayJson(rhs, "unique"))) {
return false;
}
if (! TRI_CheckSameValueJson(TRI_LookupArrayJson(lhs, "fields"),
TRI_LookupArrayJson(rhs, "fields"))) {
return false;
}
if (! TRI_CheckSameValueJson(TRI_LookupArrayJson(lhs, "geoJson"),
TRI_LookupArrayJson(rhs, "geoJson"))) {
return false;
}
return true;
}
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief ensure a geo index, coordinator case
////////////////////////////////////////////////////////////////////////////////
#ifdef TRI_ENABLE_CLUSTER
static v8::Handle<v8::Value> EnsureGeoIndex1Coordinator (TRI_vocbase_col_t const* col,
bool create,
bool unique,
bool geoJson,
bool ignoreNull,
char const* location) {
v8::HandleScope scope;
string const databaseName(col->_dbName);
string const cid = StringUtils::itoa(col->_cid);
ClusterInfo* ci = ClusterInfo::instance();
TRI_json_t* json = TRI_CreateArrayJson(TRI_UNKNOWN_MEM_ZONE);
if (json == 0) {
TRI_V8_EXCEPTION_MEMORY(scope);
}
TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "type", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, "geo1"));
TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "unique", TRI_CreateBooleanJson(TRI_UNKNOWN_MEM_ZONE, unique));
TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "geoJson", TRI_CreateBooleanJson(TRI_UNKNOWN_MEM_ZONE, geoJson));
TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "constraint", TRI_CreateBooleanJson(TRI_UNKNOWN_MEM_ZONE, unique));
if (unique) {
TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "ignoreNull", TRI_CreateBooleanJson(TRI_UNKNOWN_MEM_ZONE, ignoreNull));
}
TRI_json_t* flds = TRI_CreateList2Json(TRI_UNKNOWN_MEM_ZONE, 1);
if (flds == 0) {
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
TRI_V8_EXCEPTION_MEMORY(scope);
}
TRI_PushBack3ListJson(TRI_UNKNOWN_MEM_ZONE, flds, TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, location));
TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "fields", flds);
TRI_json_t* resultJson = 0;
string errorMsg;
int myerrno = ci->ensureIndexCoordinator(databaseName,
cid,
json,
create,
&CompareGeoIndex1Coordinator,
resultJson,
errorMsg,
360.0);
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
if (myerrno != TRI_ERROR_NO_ERROR) {
TRI_V8_EXCEPTION_MESSAGE(scope, myerrno, errorMsg);
}
if (resultJson == 0) {
TRI_V8_EXCEPTION_MEMORY(scope);
}
// TODO: protect against races on _name
v8::Handle<v8::Value> index = IndexRep(col->_name, resultJson);
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, resultJson);
return scope.Close(index);
}
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief index comparator, used by the coordinator to detect if two index
/// contents are the same
////////////////////////////////////////////////////////////////////////////////
#ifdef TRI_ENABLE_CLUSTER
static bool CompareGeoIndex2Coordinator (TRI_json_t const* lhs,
TRI_json_t const* rhs) {
if (! TRI_CheckSameValueJson(TRI_LookupArrayJson(lhs, "unique"),
TRI_LookupArrayJson(rhs, "unique"))) {
return false;
}
if (! TRI_CheckSameValueJson(TRI_LookupArrayJson(lhs, "fields"),
TRI_LookupArrayJson(rhs, "fields"))) {
return false;
}
return true;
}
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief ensure a geo index, coordinator case
////////////////////////////////////////////////////////////////////////////////
#ifdef TRI_ENABLE_CLUSTER
static v8::Handle<v8::Value> EnsureGeoIndex2Coordinator (TRI_vocbase_col_t const* col,
bool create,
bool unique,
bool ignoreNull,
char const* latitude,
char const* longitude) {
v8::HandleScope scope;
string const databaseName(col->_dbName);
string const cid = StringUtils::itoa(col->_cid);
ClusterInfo* ci = ClusterInfo::instance();
TRI_json_t* json = TRI_CreateArrayJson(TRI_UNKNOWN_MEM_ZONE);
if (json == 0) {
TRI_V8_EXCEPTION_MEMORY(scope);
}
TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "type", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, "geo2"));
TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "unique", TRI_CreateBooleanJson(TRI_UNKNOWN_MEM_ZONE, unique));
TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "constraint", TRI_CreateBooleanJson(TRI_UNKNOWN_MEM_ZONE, unique));
if (unique) {
TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "ignoreNull", TRI_CreateBooleanJson(TRI_UNKNOWN_MEM_ZONE, ignoreNull));
}
TRI_json_t* flds = TRI_CreateList2Json(TRI_UNKNOWN_MEM_ZONE, 2);
if (flds == 0) {
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
TRI_V8_EXCEPTION_MEMORY(scope);
}
TRI_PushBack3ListJson(TRI_UNKNOWN_MEM_ZONE, flds, TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, latitude));
TRI_PushBack3ListJson(TRI_UNKNOWN_MEM_ZONE, flds, TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, longitude));
TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "fields", flds);
TRI_json_t* resultJson = 0;
string errorMsg;
int myerrno = ci->ensureIndexCoordinator(databaseName,
cid,
json,
create,
&CompareGeoIndex2Coordinator,
resultJson,
errorMsg,
360.0);
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
if (myerrno != TRI_ERROR_NO_ERROR) {
TRI_V8_EXCEPTION_MESSAGE(scope, myerrno, errorMsg);
}
if (resultJson == 0) {
TRI_V8_EXCEPTION_MEMORY(scope);
}
// TODO: protect against races on _name
v8::Handle<v8::Value> index = IndexRep(col->_name, resultJson);
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, resultJson);
return scope.Close(index);
}
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief ensures that a geo index or constraint exists
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> EnsureGeoIndexVocbaseCol (v8::Arguments const& argv, bool unique) {
v8::HandleScope scope;
PREVENT_EMBEDDED_TRANSACTION(scope);
TRI_vocbase_col_t const* col = TRI_UnwrapClass<TRI_vocbase_col_t>(argv.Holder(), WRP_VOCBASE_COL_TYPE);
v8::Handle<v8::Object> err;
TRI_vocbase_col_t const* collection = UseCollection(argv.Holder(), &err);
if (collection == 0) {
return scope.Close(v8::ThrowException(err));
if (col == 0) {
TRI_V8_EXCEPTION_INTERNAL(scope, "cannot extract collection");
}
TRI_primary_collection_t* primary = collection->_collection;
TRI_document_collection_t* document = (TRI_document_collection_t*) primary;
TRI_vocbase_t* vocbase = col->_vocbase;
assert(vocbase != 0);
TRI_index_t* idx = 0;
bool created;
int off = unique ? 1 : 0;
bool ignoreNull = false;
// .............................................................................
// case: <location>
// .............................................................................
@ -2692,15 +2884,30 @@ static v8::Handle<v8::Value> EnsureGeoIndexVocbaseCol (v8::Arguments const& argv
TRI_Utf8ValueNFC loc(TRI_UNKNOWN_MEM_ZONE, argv[0]);
if (*loc == 0) {
ReleaseCollection(collection);
TRI_V8_EXCEPTION_PARAMETER(scope, "<location> must be an attribute path");
}
if (unique) {
ignoreNull = TRI_ObjectToBoolean(argv[1]);
}
#ifdef TRI_ENABLE_CLUSTER
if (ServerState::instance()->isCoordinator()) {
v8::Handle<v8::Value> ret = EnsureGeoIndex1Coordinator(col, true, unique, false, ignoreNull, *loc);
return scope.Close(ret);
}
#endif
CollectionNameResolver resolver(vocbase);
ReadTransactionType trx(vocbase, resolver, col->_cid);
idx = TRI_EnsureGeoIndex1DocumentCollection(document,
int res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {
TRI_V8_EXCEPTION(scope, res);
}
idx = TRI_EnsureGeoIndex1DocumentCollection((TRI_document_collection_t*) trx.primaryCollection(),
*loc,
false,
unique,
@ -2717,15 +2924,30 @@ static v8::Handle<v8::Value> EnsureGeoIndexVocbaseCol (v8::Arguments const& argv
TRI_Utf8ValueNFC loc(TRI_UNKNOWN_MEM_ZONE, argv[0]);
if (*loc == 0) {
ReleaseCollection(collection);
TRI_V8_EXCEPTION_PARAMETER(scope, "<location> must be an attribute path");
}
if (unique) {
ignoreNull = TRI_ObjectToBoolean(argv[2]);
}
#ifdef TRI_ENABLE_CLUSTER
if (ServerState::instance()->isCoordinator()) {
v8::Handle<v8::Value> ret = EnsureGeoIndex1Coordinator(col, true, unique, TRI_ObjectToBoolean(argv[1]), ignoreNull, *loc);
return scope.Close(ret);
}
#endif
CollectionNameResolver resolver(vocbase);
ReadTransactionType trx(vocbase, resolver, col->_cid);
idx = TRI_EnsureGeoIndex1DocumentCollection(document,
int res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {
TRI_V8_EXCEPTION(scope, res);
}
idx = TRI_EnsureGeoIndex1DocumentCollection((TRI_document_collection_t*) trx.primaryCollection(),
*loc,
TRI_ObjectToBoolean(argv[1]),
unique,
@ -2743,20 +2965,34 @@ static v8::Handle<v8::Value> EnsureGeoIndexVocbaseCol (v8::Arguments const& argv
TRI_Utf8ValueNFC lon(TRI_UNKNOWN_MEM_ZONE, argv[1]);
if (*lat == 0) {
ReleaseCollection(collection);
TRI_V8_EXCEPTION_PARAMETER(scope, "<latitude> must be an attribute path");
}
if (*lon == 0) {
ReleaseCollection(collection);
TRI_V8_EXCEPTION_PARAMETER(scope, "<longitude> must be an attribute path");
}
if (unique) {
ignoreNull = TRI_ObjectToBoolean(argv[2]);
}
#ifdef TRI_ENABLE_CLUSTER
if (ServerState::instance()->isCoordinator()) {
v8::Handle<v8::Value> ret = EnsureGeoIndex2Coordinator(col, true, unique, ignoreNull, *lat, *lon);
return scope.Close(ret);
}
#endif
CollectionNameResolver resolver(vocbase);
ReadTransactionType trx(vocbase, resolver, col->_cid);
idx = TRI_EnsureGeoIndex2DocumentCollection(document,
int res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {
TRI_V8_EXCEPTION(scope, res);
}
idx = TRI_EnsureGeoIndex2DocumentCollection((TRI_document_collection_t*) trx.primaryCollection(),
*lat,
*lon,
unique,
@ -2770,8 +3006,6 @@ static v8::Handle<v8::Value> EnsureGeoIndexVocbaseCol (v8::Arguments const& argv
// .............................................................................
else {
ReleaseCollection(collection);
if (unique) {
TRI_V8_EXCEPTION_USAGE(
scope,
@ -2786,25 +3020,24 @@ static v8::Handle<v8::Value> EnsureGeoIndexVocbaseCol (v8::Arguments const& argv
}
if (idx == 0) {
ReleaseCollection(collection);
TRI_V8_EXCEPTION_MESSAGE(scope, TRI_errno(), "index could not be created");
}
TRI_json_t* json = idx->json(idx,false);
if (json == 0) {
ReleaseCollection(collection);
TRI_V8_EXCEPTION_MEMORY(scope);
}
v8::Handle<v8::Value> index = IndexRep(&primary->base, json);
// TODO: protect this from races on _name!!
v8::Handle<v8::Value> index = IndexRep(col->_name, json);
TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
if (index->IsObject()) {
index->ToObject()->Set(v8::String::New("isNewlyCreated"), v8::Boolean::New(created));
}
ReleaseCollection(collection);
return scope.Close(index);
}

View File

@ -380,6 +380,58 @@ function handleDatabaseChanges (plan, current) {
cleanupCurrentDatabases();
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create an index in a shard
////////////////////////////////////////////////////////////////////////////////
function createIndex (shard, index) {
var collection = arangodb.db._collection(shard);
switch (index.type) {
case "hash":
if (index.unique) {
collection.ensureUniqueConstraint.apply(collection, index.fields);
}
else {
collection.ensureHashIndex.apply(collection, index.fields);
}
break;
case "skiplist":
if (index.unique) {
collection.ensureUniqueSkiplist.apply(collection, index.fields);
}
else {
collection.ensureSkiplist.apply(collection, index.fields);
}
break;
case "fulltext":
collection.ensureFulltextIndex(index.fields[0], index.minLength);
break;
case "geo1":
if (index.unique) {
collection.ensureGeoConstraint(index.fields[0],
index.geoJson,
index.ignoreNull);
}
else {
collection.ensureGeoIndex(index.fields[0],
index.geoJson,
index.ignoreNull);
}
break;
case "geo2":
if (index.unique) {
collection.ensureGeoConstraint(index.fields[0],
index.fields[1],
index.ignoreNull);
}
else {
collection.ensureGeoIndex(index.fields[0], index.fields[1]);
}
break;
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create collections if they exist in the plan but not locally
////////////////////////////////////////////////////////////////////////////////
@ -526,35 +578,15 @@ function createLocalCollections (plannedCollections) {
for (idx in payload.indexes) {
if (payload.indexes.hasOwnProperty(idx)) {
if (! indexes.hasOwnProperty(payload.indexes[idx].id)) {
var c = db._collection(shard);
var index = payload.indexes[idx];
if (! indexes.hasOwnProperty(index.id)) {
console.info("creating index '%s/%s': %s",
database,
shard,
JSON.stringify(payload.indexes[idx]));
JSON.stringify(index));
switch (payload.indexes[idx].type) {
case "hash":
if (payload.indexes[idx].unique) {
c.ensureUniqueConstraint.apply(c, payload.indexes[idx].fields);
}
else {
c.ensureHashIndex.apply(c, payload.indexes[idx].fields);
}
break;
case "skiplist":
if (payload.indexes[idx].unique) {
c.ensureUniqueSkiplist.apply(c, payload.indexes[idx].fields);
}
else {
c.ensureSkiplist.apply(c, payload.indexes[idx].fields);
}
break;
case "fulltext":
c.ensureFulltextIndex(payload.indexes[idx].fields[0], payload.indexes[idx].minLength);
break;
}
createIndex(shard, index);
}
}
}