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); 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 /// @brief ensures that a geo index or constraint exists
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> EnsureGeoIndexVocbaseCol (v8::Arguments const& argv, bool unique) { static v8::Handle<v8::Value> EnsureGeoIndexVocbaseCol (v8::Arguments const& argv, bool unique) {
v8::HandleScope scope; v8::HandleScope scope;
PREVENT_EMBEDDED_TRANSACTION(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; if (col == 0) {
TRI_vocbase_col_t const* collection = UseCollection(argv.Holder(), &err); TRI_V8_EXCEPTION_INTERNAL(scope, "cannot extract collection");
if (collection == 0) {
return scope.Close(v8::ThrowException(err));
} }
TRI_primary_collection_t* primary = collection->_collection; TRI_vocbase_t* vocbase = col->_vocbase;
assert(vocbase != 0);
TRI_document_collection_t* document = (TRI_document_collection_t*) primary;
TRI_index_t* idx = 0; TRI_index_t* idx = 0;
bool created; bool created;
int off = unique ? 1 : 0; int off = unique ? 1 : 0;
bool ignoreNull = false; bool ignoreNull = false;
// ............................................................................. // .............................................................................
// case: <location> // 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]); TRI_Utf8ValueNFC loc(TRI_UNKNOWN_MEM_ZONE, argv[0]);
if (*loc == 0) { if (*loc == 0) {
ReleaseCollection(collection);
TRI_V8_EXCEPTION_PARAMETER(scope, "<location> must be an attribute path"); TRI_V8_EXCEPTION_PARAMETER(scope, "<location> must be an attribute path");
} }
if (unique) { if (unique) {
ignoreNull = TRI_ObjectToBoolean(argv[1]); 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, *loc,
false, false,
unique, unique,
@ -2717,15 +2924,30 @@ static v8::Handle<v8::Value> EnsureGeoIndexVocbaseCol (v8::Arguments const& argv
TRI_Utf8ValueNFC loc(TRI_UNKNOWN_MEM_ZONE, argv[0]); TRI_Utf8ValueNFC loc(TRI_UNKNOWN_MEM_ZONE, argv[0]);
if (*loc == 0) { if (*loc == 0) {
ReleaseCollection(collection);
TRI_V8_EXCEPTION_PARAMETER(scope, "<location> must be an attribute path"); TRI_V8_EXCEPTION_PARAMETER(scope, "<location> must be an attribute path");
} }
if (unique) { if (unique) {
ignoreNull = TRI_ObjectToBoolean(argv[2]); 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, *loc,
TRI_ObjectToBoolean(argv[1]), TRI_ObjectToBoolean(argv[1]),
unique, unique,
@ -2743,20 +2965,34 @@ static v8::Handle<v8::Value> EnsureGeoIndexVocbaseCol (v8::Arguments const& argv
TRI_Utf8ValueNFC lon(TRI_UNKNOWN_MEM_ZONE, argv[1]); TRI_Utf8ValueNFC lon(TRI_UNKNOWN_MEM_ZONE, argv[1]);
if (*lat == 0) { if (*lat == 0) {
ReleaseCollection(collection);
TRI_V8_EXCEPTION_PARAMETER(scope, "<latitude> must be an attribute path"); TRI_V8_EXCEPTION_PARAMETER(scope, "<latitude> must be an attribute path");
} }
if (*lon == 0) { if (*lon == 0) {
ReleaseCollection(collection);
TRI_V8_EXCEPTION_PARAMETER(scope, "<longitude> must be an attribute path"); TRI_V8_EXCEPTION_PARAMETER(scope, "<longitude> must be an attribute path");
} }
if (unique) { if (unique) {
ignoreNull = TRI_ObjectToBoolean(argv[2]); 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, *lat,
*lon, *lon,
unique, unique,
@ -2770,8 +3006,6 @@ static v8::Handle<v8::Value> EnsureGeoIndexVocbaseCol (v8::Arguments const& argv
// ............................................................................. // .............................................................................
else { else {
ReleaseCollection(collection);
if (unique) { if (unique) {
TRI_V8_EXCEPTION_USAGE( TRI_V8_EXCEPTION_USAGE(
scope, scope,
@ -2786,25 +3020,24 @@ static v8::Handle<v8::Value> EnsureGeoIndexVocbaseCol (v8::Arguments const& argv
} }
if (idx == 0) { if (idx == 0) {
ReleaseCollection(collection);
TRI_V8_EXCEPTION_MESSAGE(scope, TRI_errno(), "index could not be created"); TRI_V8_EXCEPTION_MESSAGE(scope, TRI_errno(), "index could not be created");
} }
TRI_json_t* json = idx->json(idx,false); TRI_json_t* json = idx->json(idx,false);
if (json == 0) { if (json == 0) {
ReleaseCollection(collection);
TRI_V8_EXCEPTION_MEMORY(scope); 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); TRI_FreeJson(TRI_CORE_MEM_ZONE, json);
if (index->IsObject()) { if (index->IsObject()) {
index->ToObject()->Set(v8::String::New("isNewlyCreated"), v8::Boolean::New(created)); index->ToObject()->Set(v8::String::New("isNewlyCreated"), v8::Boolean::New(created));
} }
ReleaseCollection(collection);
return scope.Close(index); return scope.Close(index);
} }

View File

@ -380,6 +380,58 @@ function handleDatabaseChanges (plan, current) {
cleanupCurrentDatabases(); 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 /// @brief create collections if they exist in the plan but not locally
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -526,35 +578,15 @@ function createLocalCollections (plannedCollections) {
for (idx in payload.indexes) { for (idx in payload.indexes) {
if (payload.indexes.hasOwnProperty(idx)) { if (payload.indexes.hasOwnProperty(idx)) {
if (! indexes.hasOwnProperty(payload.indexes[idx].id)) { var index = payload.indexes[idx];
var c = db._collection(shard);
if (! indexes.hasOwnProperty(index.id)) {
console.info("creating index '%s/%s': %s", console.info("creating index '%s/%s': %s",
database, database,
shard, shard,
JSON.stringify(payload.indexes[idx])); JSON.stringify(index));
switch (payload.indexes[idx].type) { createIndex(shard, index);
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;
}
} }
} }
} }