herr_t
ss_pers_update(ss_pers_t *pers)
{
SS_ENTER(ss_pers_update, herr_t);
ss_gfile_t *gfile=NULL; /* The GFile array entry for the file that owns the object */
ss_table_t *table=NULL; /* The scope table or the resulting object's table */
ss_scopeobj_t *scopeobj=NULL; /* The scope object owning the desired object */
ss_persobj_t *persobj=NULL; /* A pointer to the persistent object to be returned */
size_t objidx; /* An index into a table for the object in question */
unsigned tableidx; /* Object magic serial number for table */
SS_ASSERT(pers);
SS_ASSERT_CLASS(pers, ss_pers_t);
if (SS_PERS_LINK_NULL==ss_pers_link_state(pers)) goto done;
if (SS_PERS_LINK_RESERVED==ss_pers_link_state(pers)) goto done;
if (NULL==(gfile=SS_GFILE_LINK(pers))) goto done;
if (gfile->cur_open>0 ||
(gfile->topscope && SS_MAGIC(ss_scope_t)==SS_MAGIC_OF(pers))) {
/* The file is currently open (or the file was previously open and we're updating a scope link) but the object in
* question may not yet be in memory if its table has never been read by this task. If the object is in memory then
* make sure the link has the current address and object index, otherwise make the link a `closed' link. */
/* Scope tables are never deleted when a scope is closed, therefore there is no need to consult the `open_serial'
* number of such a link to determine if the cached object pointer is out of date. In fact, doing so would cause
* infinite recursion when the ss_scope_table() just below tries to dereference gfile->topscope. */
if (SS_MAGIC_OF(pers)==SS_MAGIC(ss_scope_t)) ss_pers_link_setopenserial(pers, gfile->open_serial);
/* If the link is in the memory state and the object to which it points agrees has a `mapidx' that agrees with the
* object index stored in the link itself, then short circuit in order to prevent infinite recursion between this
* function and ss_pers_deref(). */
if (SS_PERS_LINK_MEMORY==ss_pers_link_state(pers) &&
gfile->open_serial==ss_pers_link_openserial(pers) &&
NULL!=(persobj=ss_pers_link_objptr(pers)) &&
persobj->mapidx==ss_pers_link_objidx(pers)) goto done;
/* Get the object's scope */
if (NULL==(table=ss_scope_table(gfile->topscope, SS_MAGIC(ss_scope_t), NULL))) SS_ERROR(FAILED);
if (NULL==(scopeobj=(ss_scopeobj_t*)ss_table_lookup(table, ss_pers_link_scopeidx(pers), SS_STRICT))) SS_ERROR(FAILED);
/* Get the object's table */
tableidx = SS_MAGIC_SEQUENCE(SS_MAGIC_OF(pers));
if (NULL==(table=scopeobj->m.table[tableidx])) SS_ERROR(NOTFOUND);
/* See if the object is in memory already. This has the side effect of allocating memory for the object although it
* won't actually read the object from the file. If the object isn't in memory yet then the link must necessarily have
* a direct object index. */
if (NULL==(persobj=ss_table_lookup(table, ss_pers_link_objidx(pers), 0))) SS_ERROR(FAILED);
if (SS_MAGIC_CLASS(SS_MAGIC_OF(persobj))!=SS_MAGIC(ss_persobj_t)) {
/* Not in memory */
SS_ASSERT(0==(ss_pers_link_objidx(pers) & SS_TABLE_INDIRECT));
ss_pers_link_setstate(pers, SS_PERS_LINK_CLOSED);
ss_pers_link_setobjptr(pers, NULL);
ss_pers_link_setopenserial(pers, gfile->open_serial);
} else {
/* In memory */
ss_pers_link_setstate(pers, SS_PERS_LINK_MEMORY);
ss_pers_link_setobjidx(pers, persobj->mapidx);
ss_pers_link_setobjptr(pers, persobj);
ss_pers_link_setopenserial(pers, gfile->open_serial);
}
} else if (gfile->topscope) {
/* File was open before but now is closed. It's scopes are still in memory however and we can use that to make sure
* that the link has a direct object index. */
/* Get the object's scope */
if (NULL==(table=ss_scope_table(gfile->topscope, SS_MAGIC(ss_scope_t), NULL))) SS_ERROR(FAILED);
if (NULL==(scopeobj=(ss_scopeobj_t*)ss_table_lookup(table, ss_pers_link_scopeidx(pers), SS_STRICT))) SS_ERROR(FAILED);
/* Get the object's table. */
tableidx = SS_MAGIC_SEQUENCE(SS_MAGIC_OF(pers));
if (NULL==(table=scopeobj->m.table[tableidx])) SS_ERROR(NOTFOUND);
/* Make the link a `closed' link and use the direct index */
ss_pers_link_setstate(pers, SS_PERS_LINK_CLOSED);
ss_pers_link_setobjptr(pers, NULL);
if (ss_pers_link_objidx(pers) & SS_TABLE_INDIRECT) {
if (SS_NOSIZE==(objidx=ss_table_direct(table, ss_pers_link_objidx(pers)))) SS_ERROR(FAILED);
SS_ASSERT(0==(objidx & SS_TABLE_INDIRECT)); /*if a table was closed it must have been synchronized*/
ss_pers_link_setobjidx(pers, objidx);
}
} else {
/* The destination file has never been opened. Therefore the link must already be in a closed state with a direct
* object index. */
SS_ASSERT(SS_PERS_LINK_CLOSED==ss_pers_link_state(pers));
SS_ASSERT(0==(ss_pers_link_objidx(pers) & SS_TABLE_INDIRECT));
}
done:
SS_CLEANUP:
SS_LEAVE(0);
}