1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
 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);
 }