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
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
 int
 saf_find_sets(SAF_ParMode pmode,        /* The parallel mode. */
               SAF_FindSetMode fmode,    /* The find mode. Possible values are SAF_FSETS_TOP to find the top-level set in the
                                          * subset inclusion lattice in which SET is a member; SAF_FSETS_BOUNDARY to find the
                                          * boundary of set SET; SAF_FSETS_SUBS to find all sets which are immediate subsets of SET
                                          * by the specified collection category; SAF_FSETS_SUPS to find all sets which are
                                          * immediate supersets of SET by the specified collection category; and
                                          * SAF_FSETS_LEAVES to find all leaf sets in the subset inclusion lattice rooted at
                                          * SET (a leaf set is a set that is a descendent of SET by the specified collection
                                          * category and which has no sets below it). */
               SAF_Set *set,             /* The set in the subset inclusion lattice at which to begin searching. */
               SAF_Cat *cat,             /* The collection category upon which to search for subsets, supersets, or leaf sets. */
               int *num,                 /* For this and the succeeding argument [see Returned Handles]. */
               SAF_Set **found           /* For this and the preceding argument [see Returned Handles]. */
               )
 {
     SAF_ENTER(saf_find_sets, SAF_PRECONDITION_ERROR);
     SAF_KEYMASK(SAF_Rel, relkey, relmask);
     size_t      nrelsfound;             /* Number of relations found */
     ss_rel_t    *allrels=NULL;          /* Relations that were found */
     ss_scope_t  scope=SS_SCOPE_NULL;    /* The scope of SET used to search for relations defined on SET */
     ss_rel_t    frel=SS_REL_NULL;       /* Found relation */
     ss_set_t    fset=SS_SET_NULL;       /* Found set */
     htri_t      duplicate;              /* True if Set is a duplicate or error occurs */
     ss_set_t    *subs=NULL;             /* Allocated array of subsets */
     int         nsubs=0;                /* Number of subsets in the `subs' array */
     size_t      i, j;

     SAF_REQUIRE(_saf_valid_pmode(pmode), SAF_LOW_CHK_COST, SAF_PRECONDITION_ERROR,
                 _saf_errmsg("PMODE must be valid"));
     if (!_saf_is_participating_proc(pmode)) SAF_RETURN(-1);

     SAF_REQUIRE(SS_SET(set), SAF_LOW_CHK_COST, SAF_PRECONDITION_ERROR,
                 _saf_errmsg("SET must be a valid set handle"));
     SAF_REQUIRE(fmode==SAF_FSETS_TOP || fmode==SAF_FSETS_SUBS || fmode==SAF_FSETS_SUPS || fmode==SAF_FSETS_LEAVES ||
                 fmode==SAF_FSETS_BOUNDARY,
                 SAF_LOW_CHK_COST, SAF_PRECONDITION_ERROR,
                 _saf_errmsg("FMODE must be SAF_FSETS... _TOP, _SUBS, _SUPS, _LEAVES or _BOUNDARY"));
     SAF_REQUIRE(((fmode==SAF_FSETS_SUPS || fmode==SAF_FSETS_SUBS || fmode==SAF_FSETS_LEAVES) && (SS_CAT(cat) || !cat)) ||
                 ((fmode==SAF_FSETS_TOP || fmode==SAF_FSETS_BOUNDARY) && (!cat || SAF_EQUIV(cat, SAF_NOT_APPLICABLE_CAT))),
                 SAF_LOW_CHK_COST, SAF_PRECONDITION_ERROR,
                 _saf_errmsg("CAT arg applicable only for SAF_FSETS_SUPS, SAF_FSETS_SUBS and SAF_FSETS_LEAVES modes"));

     /* For recursive SAF_FSETS_LEAVES calls to this function the _saf_valid_memhints() doesn't apply as both are null ptrs. */
     SAF_REQUIRE((SAF_FSETS_LEAVES==fmode && saf_find_sets_g.depth>0) ||
                 _saf_valid_memhints(num, (void**)found), SAF_LOW_CHK_COST, SAF_PRECONDITION_ERROR,
                 _saf_errmsg("NUM and FOUND must be compatible for return value allocation"));
     SAF_REQUIRE(fmode!=SAF_FSETS_LEAVES || saf_find_sets_g.depth>0 || num, SAF_LOW_CHK_COST, SAF_PRECONDITION_ERROR,
                 _saf_errmsg("NUM is required in a top-level SAF_FSETS_LEAVES mode call"));

     /* ISSUE: This function looks for Relations only in the same scope that stores SET and thus cannot traverse a subset
      *        inclusion lattice that extends outside that scope. [rpm 2004-06-21] */
     ss_pers_scope((ss_pers_t*)set, &scope);

     switch (fmode) {
     case SAF_FSETS_BOUNDARY:
         if (found && !*found && NULL==(*found=calloc(1, sizeof(**found))))
             SAF_ERROR(SAF_MEMORY_ERROR,_saf_errmsg("cannot allocate Set return value"));
         if (!SS_PERS_ISNULL(SS_SET_P(set,bnd_set))) {
             if (num) *num = 1;
             if (found) (*found)[0] = SS_SET(set)->bnd_set;
         } else {
             if (num) *num = 0;
         }
         break;

     case SAF_FSETS_TOP:
         /* fill in search criteria */
         SAF_SEARCH(SAF_Rel, relkey, relmask, kind, SAF_RELKIND_EQUAL);
         if (!SS_PERS_ISNULL(cat)) {
             SAF_SEARCH(SAF_Rel, relkey, relmask, sub_cat, *cat);
             SAF_SEARCH(SAF_Rel, relkey, relmask, sup_cat, *cat);
         }

         /* loop until found a top */
         fset = *set;
         while (1) {
            /* Did we found the top? */
             if (SS_SET(&fset)->is_top && SS_SET(&fset)->srole==SS_SET(set)->srole) {
                 if (num) *num = 1;
                 if (found && !*found && NULL==(*found=calloc(1, sizeof(**found))))
                     SAF_ERROR(SAF_MEMORY_ERROR,_saf_errmsg("cannot allocate Set return value"));
                 (*found)[0] = fset;
                 break;
             }

             /* Find the next set up */
             SAF_SEARCH(SAF_Rel, relkey, relmask, sub, fset);
             nrelsfound=1;
             if (NULL==ss_pers_find(&scope, (ss_pers_t*)relkey, (ss_persobj_t*)&relmask, (size_t)0, &nrelsfound,
                                    (ss_pers_t*)&frel, NULL))
                 SAF_ERROR(SAF_FILE_ERROR,_saf_errmsg("find failed"));
             if (nrelsfound!=1)
                 SAF_ERROR(SAF_CONSTRAINT_ERROR,_saf_errmsg("unable to find a top for set \"%s\"",
                                                            ss_string_ptr(SS_SET_P(set,name))));
             fset = SS_REL(&frel)->sup;
         }
         break;

     case SAF_FSETS_SUBS:
     case SAF_FSETS_SUPS:
         /* Fill in search criteria. */
         if (fmode == SAF_FSETS_SUBS) {
             SAF_SEARCH(SAF_Rel, relkey, relmask, sup, *set);
         } else {
             SAF_SEARCH(SAF_Rel, relkey, relmask, sub, *set);
         }
         SAF_SEARCH(SAF_Rel, relkey, relmask, kind, SAF_RELKIND_EQUAL);
         if (!SS_PERS_ISNULL(cat)) {
             SAF_SEARCH(SAF_Rel, relkey, relmask, sub_cat, *cat);
             SAF_SEARCH(SAF_Rel, relkey, relmask, sup_cat, *cat);
         }

         /* Find matching relations */
         nrelsfound = SS_NOSIZE;
         allrels = (ss_rel_t*)ss_pers_find(&scope, (ss_pers_t*)relkey, (ss_persobj_t*)&relmask, (size_t)0, &nrelsfound, NULL, NULL);
         if (!allrels)
             SAF_ERROR(SAF_FILE_ERROR, _saf_errmsg("failed when finding relations associated with the set"));

         /* If the category is SAF_ANY_CAT, then allrels[] will hold a link to each relation of the scope, regardless of
          * category. This means we might end up with sets listed multiple times. We must prune the list of sets so that
          * each set is mentioned at most one time. This fixes HYPer02781: saf_find_sets() won't accept SAF_ANY CAT. */
         for (i=1; i<nrelsfound; i++) {
             if (SAF_FSETS_SUPS==fmode) {
                 for (j=0, duplicate=FALSE; j<i && !duplicate; j++)
                     duplicate = SS_PERS_EQ(SS_REL_P(allrels+j,sup), SS_REL_P(allrels+i,sup));
             } else {
                 for (j=0, duplicate=FALSE; j<i && !duplicate; j++)
                     duplicate = SS_PERS_EQ(SS_REL_P(allrels+j,sub), SS_REL_P(allrels+i,sub));
             }
             if (duplicate) {
                 allrels[i] = allrels[nrelsfound-1]; /*replace current rel with the last rel*/
                 --nrelsfound; /*we discarded one relation*/
                 --i; /*repeat loop at current location*/
             }
         }

         /* Return what the caller asked for. */
         if (!found) {
             /* Count the matches */
             assert(num);
             *num = nrelsfound;
         } else if (!*found) {
             /* Find all matches; library allocates results */
             if (NULL==(*found=malloc(MAX(nrelsfound,1)*sizeof(**found))))
                 SAF_ERROR(SAF_MEMORY_ERROR, _saf_errmsg("unable to allocate return value"));
             if (num) *num = nrelsfound;
         } else {
             /* Find limited matches; client allocates result buffer */
             assert(num);
             if (nrelsfound>(size_t)*num)
                 SAF_ERROR(SAF_CONSTRAINT_ERROR, _saf_errmsg("found too many matching objects"));
             *num = nrelsfound;
         }
         if (found) {
             for (i=0; i<nrelsfound; i++) {
                 if (SAF_FSETS_SUBS==fmode) {
                     (*found)[i] = SS_REL(allrels+i)->sub;
                 } else {
                     (*found)[i] = SS_REL(allrels+i)->sup;
                 }
             }
         }
         break;

     case SAF_FSETS_LEAVES:
         /* Finding the leaves is a recursive operation: For the given set, find the leaves of all its subsets and merge those
          * lists, removing duplicates. */

         /* ISSUE: For a SAF_FSETS_LEAVES search with a null collection category (SAF_ANY_CAT) this function will return a list
          *        of unique sets by pruning out the duplicates. However, the pruning occurs down at the leaves and not in the
          *        internal nodes of the graph, and therefore we may end up traversing portions of the graph repeatedly.
          *        [rpm 2004-06-21] */

         if (0==saf_find_sets_g.depth)
             memset(&saf_find_sets_g, 0, sizeof saf_find_sets_g);

         /* Make sure this set isn't already in the list of sets to be returned. */
         for (i=0, duplicate=FALSE; i<saf_find_sets_g.nused && !duplicate; i++) {
             duplicate = SS_PERS_EQ(set, saf_find_sets_g.sets+i);
         }
         if (duplicate) {
             if (num) *num = 0;
             goto done;
         }

         /* Find this set's subsets */
         subs = NULL;
         saf_find_sets(pmode, SAF_FSETS_SUBS, set, cat, &nsubs, &subs);

         if (0==nsubs) {
             /* This set has no subsets: it must be a leaf. Add it to the list of sets since we already know it's not a
              * duplicate of anything in that list. */
             if (saf_find_sets_g.nused>=saf_find_sets_g.nalloc) {
                 saf_find_sets_g.nalloc = MAX(64, 2*saf_find_sets_g.nalloc);
                 if (NULL==(saf_find_sets_g.sets=realloc(saf_find_sets_g.sets,
                                                         saf_find_sets_g.nalloc*sizeof(saf_find_sets_g.sets[0]))))
                     SAF_ERROR(SAF_MEMORY_ERROR, _saf_errmsg("unable to allocate list of matching sets"));
             }
             saf_find_sets_g.sets[saf_find_sets_g.nused++] = *set;
         } else {
             /* Recursively add leaves of the subsets */
             assert(nsubs>0); /*for cast*/
             for (i=0; i<(size_t)nsubs; i++) {
                 saf_find_sets_g.depth++;
                 saf_find_sets(pmode, fmode, subs+i, cat, NULL, NULL); /*return values added to saf_find_sets_g*/
                 saf_find_sets_g.depth--;
             }
         }

         /* Free up subset list */
         subs = SS_FREE(subs);
         nsubs = 0;

         /* When the top-level call is about to return, saf_find_sets_g contains the array of sets to be returned. Either
          * return that array, copy the sets into a caller-supplied array, or just return the count. */
         if (0==saf_find_sets_g.depth) {
             if (!found) {
                 /* Count the matches */
                 assert(num);
                 *num = saf_find_sets_g.nused;
                 saf_find_sets_g.sets = SS_FREE(saf_find_sets_g.sets);
             } else if (!*found) {
                 /* Find all matches; library allocates results */
                 *found = saf_find_sets_g.sets;
                 if (num) *num = saf_find_sets_g.nused;
                 saf_find_sets_g.sets = NULL;
             } else {
                 /* Find limited matches; client allocates result buffer */
                 assert(num);
                 if ((int)saf_find_sets_g.nused>*num)
                     SAF_ERROR(SAF_CONSTRAINT_ERROR, _saf_errmsg("found too many matching objects"));
                 memcpy(*found, saf_find_sets_g.sets, saf_find_sets_g.nused*sizeof(*found));
                 *num = saf_find_sets_g.nused;
                 saf_find_sets_g.sets = SS_FREE(saf_find_sets_g.sets);
             }
             memset(&saf_find_sets_g, 0, sizeof saf_find_sets_g); /*cleanup for next call*/
         }
         break;
     }

     SS_FREE(allrels);
 done:
     SAF_LEAVE(SAF_SUCCESS);

 }