Skip to content

Commit

Permalink
First draft of distributed GET /entities - far from ready and not acc…
Browse files Browse the repository at this point in the history
…ording to 'unpublished spec'
  • Loading branch information
kzangeli committed Oct 31, 2023
1 parent 587b94a commit aec83d3
Show file tree
Hide file tree
Showing 25 changed files with 820 additions and 205 deletions.
4 changes: 2 additions & 2 deletions src/app/orionld/orionldRestServices.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ static OrionLdRestServiceSimplified getServiceV[] =
{ "/ngsi-ld/ex/v1/ping", orionldGetPing },
{ "/ngsi-ld/v1/entities/*", orionldGetEntity },
{ "/ngsi-ld/v1/entities", orionldGetEntities },
{ "/ngsi-ld/v1/entityMap/*", orionldGetEntityMap },
{ "/ngsi-ld/v1/entityMaps/*", orionldGetEntityMap },
{ "/ngsi-ld/v1/types/*", orionldGetEntityType },
{ "/ngsi-ld/v1/types", orionldGetEntityTypes },
{ "/ngsi-ld/v1/attributes/*", orionldGetEntityAttribute },
Expand Down Expand Up @@ -176,7 +176,7 @@ static OrionLdRestServiceSimplified deleteServiceV[] =
{
{ "/ngsi-ld/v1/entities/*/attrs/*", orionldDeleteAttribute },
{ "/ngsi-ld/v1/entities/*", orionldDeleteEntity },
{ "/ngsi-ld/v1/entityMap/*", orionldDeleteEntityMap },
{ "/ngsi-ld/v1/entityMaps/*", orionldDeleteEntityMap },
{ "/ngsi-ld/v1/subscriptions/*", orionldDeleteSubscription },
{ "/ngsi-ld/v1/csourceRegistrations/*", orionldDeleteRegistration },
{ "/ngsi-ld/v1/jsonldContexts/*", orionldDeleteContext },
Expand Down
4 changes: 3 additions & 1 deletion src/lib/logMsg/traceLevels.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,13 @@ typedef enum TraceLevels
LmtDistOpResponseHeaders, // HTTP headers of responses to distributed requests
LmtDistOpRequestHeaders, // HTTP headers of request of distributed requests
LmtDistOpList, // Linked list of DistOps
LmtDistOpAttributes, // The union of attributes URL-Param / Registered Attributes
LmtDistOpMerge, // Merge of responses from forwsrded requests (GET /entities)

//
// Context
//
LmtContexts = 80, // Contexts
LmtContexts = 82, // Contexts
LmtContextTree, // Context Tree
LmtContextCache, // Context Cache
LmtContextDownload, // Context Download
Expand Down
69 changes: 8 additions & 61 deletions src/lib/orionld/forwarding/distOpCreate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,66 +27,12 @@
#include "logMsg/logMsg.h" // LM_*

#include "orionld/common/orionldState.h" // orionldState
#include "orionld/types/StringArray.h" // StringArray
#include "orionld/context/orionldContextItemAliasLookup.h" // orionldContextItemAliasLookup
#include "orionld/types/StringArray.h" // StringArray, stringArrayClone
#include "orionld/forwarding/DistOp.h" // DistOp
#include "orionld/forwarding/DistOpType.h" // DistOpType



// -----------------------------------------------------------------------------
//
// attrsParam -
//
static void attrsParam(DistOp* distOpP, StringArray* attrList, bool permanent)
{
//
// The attributes are in longnames but ... should probably compact them.
// A registration can have its own @context, in cSourceInfo - for now, we use the @context of the original request.
// The attrList is always cloned, so, no problem modifying it.
//
int attrsLen = 0;
for (int ix = 0; ix < attrList->items; ix++)
{
attrList->array[ix] = orionldContextItemAliasLookup(orionldState.contextP, attrList->array[ix], NULL, NULL);
attrsLen += strlen(attrList->array[ix]) + 1;
}

// Make room for "attrs=" and the string-end zero
attrsLen += 7;

char* attrs = (char*) ((permanent == true)? malloc(attrsLen) : kaAlloc(&orionldState.kalloc, attrsLen));

if (attrs == NULL)
LM_X(1, ("Out of memory"));

bzero(attrs, attrsLen);

strcpy(attrs, "attrs=");

int pos = 6;
for (int ix = 0; ix < attrList->items; ix++)
{
int len = strlen(attrList->array[ix]);
strcpy(&attrs[pos], attrList->array[ix]);

// Add comma unless it's the last attr (in which case we add a zero, just in case)
pos += len;

if (ix != attrList->items - 1) // Not the last attr
{
attrs[pos] = ',';
pos += 1;
}
else
attrs[pos] = 0;
}

distOpP->attrsParam = attrs;
distOpP->attrsParamLen = pos;
}


extern void attrsParam(DistOp* distOpP, StringArray* attrList, bool permanent);

// -----------------------------------------------------------------------------
//
Expand All @@ -98,7 +44,7 @@ DistOp* distOpCreate
RegCacheItem* regP,
StringArray* idList,
StringArray* typeList,
StringArray* attrList,
StringArray* attrList, // As it arrives in the GET request (URL param 'attrs')
bool permanent
)
{
Expand All @@ -111,13 +57,14 @@ DistOp* distOpCreate

distOpP->regP = regP;
distOpP->operation = operation;
distOpP->attrList = attrList;
distOpP->idList = idList;
distOpP->typeList = typeList;

// Fix the comma-separated attribute list
attrList = (attrList != NULL)? stringArrayClone(attrList) : NULL;
if ((attrList != NULL) && (attrList->items > 0))
attrsParam(distOpP, attrList, permanent);
attrsParam(distOpP, attrList, true);
else
distOpP->attrsParam = NULL;

// Assign an ID to this DistOp
if (regP != NULL)
Expand All @@ -126,7 +73,7 @@ DistOp* distOpCreate
++orionldState.distOpNo;
}
else
strncpy(distOpP->id, "local", sizeof(distOpP->id));
strncpy(distOpP->id, "@none", sizeof(distOpP->id));

if (distOpP->regP != NULL)
LM_T(LmtDistOpList, ("Created distOp '%s', for reg '%s'", distOpP->id, distOpP->regP->regId));
Expand Down
66 changes: 42 additions & 24 deletions src/lib/orionld/forwarding/distOpEntityMerge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ static KjNode* newerAttribute(KjNode* currentP, KjNode* pretenderP)
//
// distOpEntityMerge -
//
// FIXME: createdAt and modifiedAt should be converted to floats before comparing!
//
void distOpEntityMerge(KjNode* apiEntityP, KjNode* additionP, bool sysAttrs, bool auxiliary)
{
KjNode* idP = kjLookup(additionP, "id");
Expand Down Expand Up @@ -141,46 +143,62 @@ void distOpEntityMerge(KjNode* apiEntityP, KjNode* additionP, bool sysAttrs, boo
{
next = attrP->next;

KjNode* currentP = kjLookup(apiEntityP, attrP->name);
KjNode* currentP = kjLookup(apiEntityP, attrP->name);
bool createdAt = strcmp(attrP->name, "createdAt") == 0;
bool modifiedAt = strcmp(attrP->name, "modifiedAt") == 0;

if (currentP == NULL)
{
LM_T(LmtDistOpMerge, ("New Attribute '%s' - adding it to the entity", attrP->name));
kjChildRemove(additionP, attrP);
kjChildAdd(apiEntityP, attrP);
}
else if (createdAt == true) // Special attribute - need to keep the oldest, not the newest
{
LM_T(LmtDistOpMerge, ("'createdAt' in any type of registration"));
LM_T(LmtDistOpMerge, ("Current createdAt: %s", currentP->value.s));
LM_T(LmtDistOpMerge, ("Candidate createdAt: %s", attrP->value.s));
if (strcmp(attrP->value.s, currentP->value.s) > 0)
{
LM_T(LmtDistOpMerge, ("Existing Attribute '%s' - keeping it as it is OLDER than the old one", attrP->name));
kjChildRemove(apiEntityP, currentP);
kjChildRemove(additionP, attrP);
kjChildAdd(apiEntityP, attrP);
}
else
LM_T(LmtDistOpMerge, ("Existing Attribute '%s' - ignoring it as it is NEWER than the old one", attrP->name));
}
else if (modifiedAt == true) // Special attribute - non-reified
{
LM_T(LmtDistOpMerge, ("'modifiedAt' in any type of registration"));
LM_T(LmtDistOpMerge, ("Current modifiedAt: %s", currentP->value.s));
LM_T(LmtDistOpMerge, ("Candidate modifiedAt: %s", attrP->value.s));
if (strcmp(attrP->value.s, currentP->value.s) < 0)
{
LM_T(LmtDistOpMerge, ("Existing Attribute '%s' - keeping it as it is newer than the old one", attrP->name));
kjChildRemove(apiEntityP, currentP);
kjChildRemove(additionP, attrP);
kjChildAdd(apiEntityP, attrP);
}
else
LM_T(LmtDistOpMerge, ("Existing Attribute '%s' - ignoring it as it is older than the old one", attrP->name));
}
else if (auxiliary == false) // two copies of the same attr ... and NOT from an auxiliary registration
{
LM_T(LmtDistOpMerge, ("Existing Attribute '%s' in non-Auxiliary registration", attrP->name));
if (newerAttribute(currentP, attrP) == attrP)
{
LM_T(LmtDistOpMerge, ("Existing Attribute '%s' - keeping it as it is newer than the old one", attrP->name));
kjChildRemove(apiEntityP, currentP);
kjChildRemove(additionP, attrP);
kjChildAdd(apiEntityP, attrP);
}
else
LM_T(LmtDistOpMerge, ("Existing Attribute '%s' - ignoring it as it is older than the old one", attrP->name));
}
else
LM_T(LmtDistOpMerge, ("Existing Attribute '%s' - ignoring it as the registration is Auxiliary", attrP->name));

attrP = next;
}
}



// -----------------------------------------------------------------------------
//
// distOpEntityMerge -
//
void distOpEntityMerge(KjNode* entityArray, KjNode* entityP)
{
KjNode* entityIdNode = kjLookup(entityP, "id");

if (entityIdNode == NULL)
LM_RVE(("Invalid entity in response from forwarded request"));

char* entityId = entityIdNode->value.s;

KjNode* arrayEntityP = kjEntityIdLookupInEntityArray(entityArray, entityId);

if (arrayEntityP == NULL) // Not there yet - let's add it
kjChildAdd(entityArray, entityP);
else // Need to merge the two entities
distOpEntityMerge(arrayEntityP, entityP, orionldState.uriParamOptions.sysAttrs, false);
}
8 changes: 0 additions & 8 deletions src/lib/orionld/forwarding/distOpEntityMerge.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,4 @@ extern "C"
//
extern void distOpEntityMerge(KjNode* apiEntityP, KjNode* additionP, bool sysAttrs, bool auxiliary);



// -----------------------------------------------------------------------------
//
// distOpEntityMerge -
//
extern void distOpEntityMerge(KjNode* entityArray, KjNode* entityP);

#endif // SRC_LIB_ORIONLD_FORWARDING_DISTOPENTITYMERGE_H_
2 changes: 1 addition & 1 deletion src/lib/orionld/forwarding/distOpListDebug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ void distOpListDebug2(DistOp* distOpP, const char* what)

if (distOpP->attrsParam != NULL)
{
LM_T(LmtDistOpList, (" URL Attributes: %s (len: %d)", distOpP->attrsParam, distOpP->attrsParamLen));
LM_T(LmtDistOpList, (" URL Attributes: '%s' (len: %d)", distOpP->attrsParam, distOpP->attrsParamLen));
}

if (distOpP->typeList != NULL)
Expand Down
34 changes: 11 additions & 23 deletions src/lib/orionld/forwarding/regMatchAttributesForGet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,13 @@
*/
extern "C"
{
#include "kalloc/kaStrdup.h" // kaStrdup
#include "kjson/kjLookup.h" // kjLookup
}

#include "logMsg/logMsg.h" // LM_*

#include "orionld/common/orionldState.h" // orionldState
#include "orionld/types/StringArray.h" // StringArray
#include "orionld/types/StringArray.h" // StringArray, stringArrayClone
#include "orionld/kjTree/kjStringValueLookupInArray.h" // kjStringValueLookupInArray
#include "orionld/regCache/RegCache.h" // RegCacheItem
#include "orionld/forwarding/regMatchAttributesForGet.h" // Own interface
Expand Down Expand Up @@ -76,27 +75,6 @@ static bool stringArrayRemoveItem(StringArray* saP, int ix)



// -----------------------------------------------------------------------------
//
// stringArrayClone - FIXME: Move to common/stringArrayClone.h/cpp
//
StringArray* stringArrayClone(StringArray* attrV)
{
StringArray* clone = (StringArray*) kaAlloc(&orionldState.kalloc, sizeof(StringArray));

clone->items = attrV->items;
clone->array = (char**) kaAlloc(&orionldState.kalloc, attrV->items * sizeof(char*));

for (int ix = 0; ix < clone->items; ix++)
{
clone->array[ix] = kaStrdup(&orionldState.kalloc, attrV->array[ix]);
}

return clone;
}



// -----------------------------------------------------------------------------
//
// regMatchAttributesForGet -
Expand All @@ -117,6 +95,8 @@ StringArray* regMatchAttributesForGet
{
bool allAttributes = (propertyNamesP == NULL) && (relationshipNamesP == NULL);

LM_T(LmtDistOpAttributes, ("Creating the union of attributes GET URL-Param vs Registered Attributes"));

if (allAttributes == true)
{
//
Expand All @@ -129,7 +109,10 @@ StringArray* regMatchAttributesForGet
// Now, if the query is with an "attrs" parameter, we'll create a copy of it for this DistOp
//
if (attrListP != NULL)
{
LM_T(LmtDistOpAttributes, ("Keeping the URL-Param Attributes as the registration has no attributes specified"));
return stringArrayClone(attrListP);
}
}

StringArray* sList = (StringArray*) kaAlloc(&orionldState.kalloc, sizeof(StringArray));
Expand All @@ -140,6 +123,7 @@ StringArray* regMatchAttributesForGet
// Everything matches - return an empty array
sList->items = 0;
sList->array = NULL;
LM_T(LmtDistOpAttributes, ("Using ALL Attributes as the registration has no attributes specified and the Query also not"));
return sList;
}
else if ((attrListP != NULL) && (attrListP->items > 0))
Expand All @@ -165,6 +149,7 @@ StringArray* regMatchAttributesForGet
{
for (KjNode* pName = propertyNamesP->value.firstChildP; pName != NULL; pName = pName->next)
{
LM_T(LmtDistOpAttributes, ("Adding '%s' to the attrList of the DistOp", pName->value.s));
sList->array[ix++] = pName->value.s;
}
}
Expand All @@ -173,6 +158,7 @@ StringArray* regMatchAttributesForGet
{
for (KjNode* rName = relationshipNamesP->value.firstChildP; rName != NULL; rName = rName->next)
{
LM_T(LmtDistOpAttributes, ("Adding '%s' to the attrList of the DistOp", rName->value.s));
sList->array[ix++] = rName->value.s;
}
}
Expand All @@ -195,6 +181,7 @@ StringArray* regMatchAttributesForGet
if (match == false)
continue;

LM_T(LmtDistOpAttributes, ("Adding '%s' to the attrList of the DistOp", attrListP->array[ix]));
sList->array[matches++] = attrListP->array[ix];

if (regP->mode == RegModeExclusive)
Expand All @@ -207,5 +194,6 @@ StringArray* regMatchAttributesForGet
sList->items = matches;
}

LM_T(LmtDistOpAttributes, ("Returning an attrList of %d items", sList->items));
return sList;
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ extern "C"
#include "orionld/forwarding/regMatchInformationItemForGet.h" // Own interface



extern void attrsParam(DistOp* distOpP, StringArray* attrList, bool permanent);
// -----------------------------------------------------------------------------
//
// regMatchInformationArrayForGet -
Expand All @@ -57,6 +57,9 @@ DistOp* regMatchInformationArrayForGet(RegCacheItem* regP, const char* entityId,
// If we get this far, then it's a match and we can create the DistOp item and return
DistOp* distOpP = distOpCreate(DoQueryEntity, regP, NULL, NULL, attrList, false);

if ((distOpP->attrList != NULL) && (distOpP->attrList->items > 0))
attrsParam(distOpP, distOpP->attrList, true);

distOpP->geometryProperty = (char*) geoProp;

return distOpP;
Expand Down
Loading

0 comments on commit aec83d3

Please sign in to comment.