/*
* iSNS object relationships
*
* Relations are used to express a connection between two
* objects. Currently, two relationship types are implemented:
*
* - portal group: this relates a storage node and a portal
* - visibility: this relates a nodes nodes that share a
* common discovery domain.
*
* Relation objects are nice for portals groups, but kind of
* awkward for DDs. A better way of expressing DD membership
* (which also allows for a fast visibility check) could be
* to store a [bit] vector of DD IDs in each storage node.
* A visibility check would amount to just doing the bitwise
* AND of two vectors, and checking for NULL. The only thing
* to take care of would be to make sure a DD object takes a
* reference on its members (this is necessary so that objects
* maintain their ID/name associations even when removed from
* the database).
*
* Aug 22 2007 - changed DD code to use bit vectors. A lot
* of code in this file is now obsolete.
*
* Copyright (C) 2007 Olaf Kirch <olaf.kirch@oracle.com>
*/
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdarg.h>
#include <libisns/isns.h>
#include "objects.h"
#include <libisns/util.h>
#include "db.h"
struct isns_relation_soup {
/* For now, use one plain list. For better
* scalability, we'll need a hash table or
* something similar later. */
isns_relation_list_t irs_data;
};
static void isns_relation_list_append(isns_relation_list_t *,
isns_relation_t *);
static int isns_relation_list_remove(isns_relation_list_t *,
isns_relation_t *);
isns_relation_soup_t *
isns_relation_soup_alloc(void)
{
return isns_calloc(1, sizeof(isns_relation_soup_t));
}
void
isns_relation_add(isns_relation_soup_t *soup,
isns_relation_t *rp)
{
isns_relation_list_append(&soup->irs_data, rp);
}
isns_relation_t *
isns_relation_find_edge(isns_relation_soup_t *soup,
const isns_object_t *left,
const isns_object_t *right,
unsigned int relation_type)
{
isns_relation_list_t *list = &soup->irs_data;
unsigned int i;
for (i = 0; i < list->irl_count; ++i) {
isns_relation_t *rp = list->irl_data[i];
if (rp->ir_type != relation_type)
continue;
if (rp->ir_subordinate[0].obj == left
&& rp->ir_subordinate[1].obj == right)
return rp;
if (rp->ir_subordinate[0].obj == right
&& rp->ir_subordinate[1].obj == left)
return rp;
}
return NULL;
}
void
isns_relation_get_edge_objects(isns_relation_soup_t *soup,
const isns_object_t *left,
unsigned int relation_type,
isns_object_list_t *result)
{
isns_relation_list_t *list = &soup->irs_data;
unsigned int i;
for (i = 0; i < list->irl_count; ++i) {
isns_relation_t *rp = list->irl_data[i];
if (rp->ir_type != relation_type)
continue;
if (rp->ir_object == NULL)
continue;
if (rp->ir_subordinate[0].obj == left
|| rp->ir_subordinate[1].obj == left) {
isns_object_list_append(result,
rp->ir_object);
}
}
}
void
isns_relation_halfspace(isns_relation_soup_t *soup,
const isns_object_t *left,
unsigned int relation_type,
isns_object_list_t *result)
{
isns_relation_list_t *list = &soup->irs_data;
unsigned int i;
for (i = 0; i < list->irl_count; ++i) {
isns_relation_t *rp = list->irl_data[i];
if (rp->ir_type != relation_type)
continue;
if (rp->ir_subordinate[0].obj == left) {
isns_object_list_append(result,
rp->ir_subordinate[1].obj);
} else
if (rp->ir_subordinate[1].obj == left) {
isns_object_list_append(result,
rp->ir_subordinate[0].obj);
}
}
}
int
isns_relation_exists(isns_relation_soup_t *soup,
const isns_object_t *relating_object,
const isns_object_t *left,
const isns_object_t *right,
unsigned int relation_type)
{
isns_relation_list_t *list = &soup->irs_data;
unsigned int i;
for (i = 0; i < list->irl_count; ++i) {
isns_relation_t *rp = list->irl_data[i];
if (rp->ir_type != relation_type)
continue;
if (rp->ir_object != relating_object)
continue;
if (rp->ir_subordinate[0].obj == left
&& rp->ir_subordinate[1].obj == right)
return 1;
if (rp->ir_subordinate[0].obj == right
&& rp->ir_subordinate[1].obj == left)
return 1;
}
return 0;
}
isns_object_t *
isns_relation_get_other(const isns_relation_t *rp,
const isns_object_t *this)
{
if (rp->ir_subordinate[0].obj == this)
return rp->ir_subordinate[1].obj;
if (rp->ir_subordinate[1].obj == this)
return rp->ir_subordinate[0].obj;
return NULL;
}
void
isns_relation_remove(isns_relation_soup_t *soup,
isns_relation_t *rp)
{
isns_object_release(rp->ir_object);
rp->ir_object = NULL;
isns_relation_list_remove(&soup->irs_data, rp);
}
isns_relation_t *
isns_create_relation(isns_object_t *relating_object,
unsigned int relation_type,
isns_object_t *subordinate_object1,
isns_object_t *subordinate_object2)
{
isns_relation_t *rp;
rp = isns_calloc(1, sizeof(*rp));
rp->ir_type = relation_type;
rp->ir_users = 1;
rp->ir_object = isns_object_get(relating_object);
isns_object_reference_set(&rp->ir_subordinate[0], subordinate_object1);
isns_object_reference_set(&rp->ir_subordinate[1], subordinate_object2);
#if 0
if (relating_object) {
relating_object->ie_relation = rp;
rp->ir_users++;
}
#endif
return rp;
}
void
isns_relation_sever(isns_relation_t *rp)
{
isns_object_release(rp->ir_object);
rp->ir_object = NULL;
isns_object_reference_drop(&rp->ir_subordinate[0]);
isns_object_reference_drop(&rp->ir_subordinate[1]);
}
void
isns_relation_release(isns_relation_t *rp)
{
if (--(rp->ir_users))
return;
isns_relation_sever(rp);
isns_free(rp);
}
/*
* Check whether the relation references two dead/limbo objects.
* This is used for dead PG removal.
*/
int
isns_relation_is_dead(const isns_relation_t *rel)
{
isns_object_t *left, *right;
left = rel->ir_subordinate[0].obj;
right = rel->ir_subordinate[1].obj;
if ((left->ie_flags & ISNS_OBJECT_DEAD)
&& (right->ie_flags & ISNS_OBJECT_DEAD))
return 1;
return 0;
}
void
isns_relation_list_append(isns_relation_list_t *list,
isns_relation_t *rp)
{
if ((list->irl_count % 128) == 0) {
list->irl_data = isns_realloc(list->irl_data,
(list->irl_count + 128) * sizeof(void *));
if (list->irl_data == NULL)
isns_fatal("out of memory!\n");
}
list->irl_data[list->irl_count++] = rp;
rp->ir_users++;
}
int
isns_relation_list_remove(isns_relation_list_t *list,
isns_relation_t *rp)
{
unsigned int i, count = list->irl_count;
for (i = 0; i < count; ++i) {
if (list->irl_data[i] != rp)
continue;
if (i < count - 1)
list->irl_data[i] = list->irl_data[count-1];
isns_relation_release(rp);
list->irl_count -= 1;
return 1;
}
return 0;
}