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
 int
 saf_read_subset_relation(SAF_ParMode pmode,     /* The parallel mode. */
                          SAF_Rel *rel,          /* The relation whose data is to be read. */
                          SAF_RelTarget *target, /* Relation targeting information. */
                          void **abuf,           /* The data representing those members in the range collection (on the superset)
                                                  * that are related to the members in the domain collection (on the subset). */
                          void **bbuf            /* Optional data for boundary subsets indicating which local piece of boundary
                                                  * each member in the domain collection represents in each member of the
                                                  * range collection (see saf_declare_subset_relation()) */
                          )
 {
     SAF_ENTER(saf_read_subset_relation, SAF_PRECONDITION_ERROR);
     double              timer_start=0;          /* Timer for accumulating time spent reading data. */
     ss_set_t            sub,sup;                /* Relation's subset and superset */
     ss_collection_t     sub_coll, sup_coll;     /* Relation's sub and super collections */
     size_t              width;                  /* Number of elements in a collection `members' array */
     ss_pers_t           val;                    /* Element from a collection `members' array; link to a set hopefully. */
     hsize_t             size;                   /* Number of elements in a blob */
     hid_t               ftype=-1;               /* File datatype for a blob */
     hid_t               mtype=-1;               /* Memory datatype corresponding to `ftype' */
     int                 i;

     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_REL(rel), SAF_LOW_CHK_COST, SAF_PRECONDITION_ERROR,
                 _saf_errmsg("REL must be a valid relation handle"));
     SAF_REQUIRE(abuf, SAF_LOW_CHK_COST, SAF_PRECONDITION_ERROR,
                 _saf_errmsg("ABUF cannot be null for all participating processes"));
     SAF_ASSERT(!target, SAF_LOW_CHK_COST, SAF_NOTIMPL_ERROR,
                _saf_errmsg("Relation targeting is not implemented"));

     /* Start timer */
     if (_SAF_GLOBALS.p.TraceTimes)
         timer_start = _saf_wall_clock(false);

     /* Cache some stuff */
     sub = SS_REL(rel)->sub;
     if (NULL==_saf_getCollection_set(&sub, SS_REL_P(rel,sub_cat), &sub_coll))
         SAF_ERROR(SAF_FILE_ERROR, _saf_errmsg("required subset collection was not available"));
     sup = SS_REL(rel)->sup;

     /* Just as in the write case, we need to do something special for the case in which the domain collection contains just 1
      * member AND is a decomposition of its containing set.  */
     if (SS_COLLECTION(&sub_coll)->count<=1 &&
         SS_COLLECTION(&sub_coll)->cell_type==SAF_CELLTYPE_SET &&
         SS_COLLECTION(&sub_coll)->is_decomp) {
         if (NULL==_saf_getCollection_set(&sup, SS_REL_P(rel,sup_cat), &sup_coll))
             SAF_ERROR(SAF_FILE_ERROR, _saf_errmsg("attempt to read non-existent collection members"));
         if (0==(width=ss_array_nelmts(SS_COLLECTION_P(&sup_coll,members))))
             SAF_ERROR(SAF_FILE_ERROR,_saf_errmsg("attempt to read non-existent collection members"));
         if (SS_COLLECTION(&sup_coll)->count!=(int)width)
             SAF_ERROR(SAF_FILE_ERROR, _saf_errmsg("apparent attempt to read members array before it's been completey filled"));

         /* Scan list of members for the one pointing to the subset and return a link to it in the array */
         for (i=0; i<SS_COLLECTION(&sup_coll)->count; i++) {
             ss_array_get(SS_COLLECTION_P(&sup_coll,members), ss_pers_tm, (size_t)i, 1, &val);
             if (SS_PERS_EQ(&val,SS_REL_P(rel,sub))) {
                 if (!*abuf && NULL==(*abuf=malloc(sizeof(size_t))))
                     SAF_ERROR(SAF_MEMORY_ERROR, _saf_errmsg("unable to allocate space to return collection members"));
                 *(size_t*)(*abuf) = i;
                 break;
             }
         }
         if (i>=SS_COLLECTION(&sup_coll)->count)
             SAF_ERROR(SAF_MEMORY_ERROR, _saf_errmsg("unable to find subset in the superset collection's member list"));
     } else {
         /*  First, read the abuf (range) data; it is *always* present either indirectly or in a blob. */
         if (ss_array_nelmts(SS_REL_P(rel,indirect_rels))>0) {
             *abuf = ss_array_get(SS_REL_P(rel,indirect_rels), ss_pers_tm, (size_t)0, SS_NOSIZE, *abuf);
             if (!*abuf) SAF_ERROR(SAF_FILE_ERROR, _saf_errmsg("problems reading indirect relation pointers"));
             mtype = H5I_INVALID_HID;
         } else if (!SS_PERS_ISNULL(SS_REL_P(rel,r_blob))) {
             /* obtain the data set type. Note, it will be same for bbuf too, needed below. */
             ss_blob_bound_f1(SS_REL_P(rel,r_blob), NULL, NULL, &size, &ftype);
             mtype = H5Tget_native_type(ftype, H5T_DIR_DEFAULT);
             H5Tclose(ftype); ftype=-1;

             /* allocate space for the abuf data or check size */
             if (!*abuf && NULL==(*abuf = malloc((size_t)size*H5Tget_size(mtype))))
                 SAF_ERROR(SAF_MEMORY_ERROR, _saf_errmsg("unable to allocate space to read abuf of relation"));

             /* read the data */
             ss_blob_bind_m1(SS_REL_P(rel,r_blob), *abuf, mtype, size);
             ss_blob_read1(SS_REL_P(rel,r_blob), (hsize_t)0, size, SS_BLOB_UNBIND, NULL);
         } else {
             SAF_ERROR(SAF_FILE_ERROR, _saf_errmsg("attempt to read non-existent range data"));
         }

         /* Read the bbuf (domain) data */
         if (bbuf) {
             /* Issue: If the client requests BBUF but none was written, is that an error? Unfortunately, the only answer that
              *        works in all cases is to declare this an error. This is so because it is not possible to notify the client
              *        that none was written except by returning *BBUF==NULL and that is *not* possible in the case that the client
              *        has pre-allocated BBUF (except if we opt to free the pre-allocated BBUF, and then set it to NULL which I
              *        don't think would be a good idea). We limit returning error to *only* this case. The other case returns
              *        BBUF==NULL */
             if (SS_PERS_ISNULL(SS_REL_P(rel,d_blob))) {
                 if (*bbuf)
                     SAF_ERROR(SAF_FILE_ERROR, _saf_errmsg("attempt to read non-existent bbuf blob into pre-allocated memory"));
             } else {
                 /* allocate space for the bbuf data or check size */
                 ss_blob_bound_f1(SS_REL_P(rel,d_blob), NULL, NULL, &size, NULL);
                 if (!*bbuf && NULL==(*bbuf=malloc((size_t)size*H5Tget_size(mtype))))
                     SAF_ERROR(SAF_MEMORY_ERROR, _saf_errmsg("unable to allocate space to read bbuf of relation"));

                 /* read the data */
                 ss_blob_bind_m1(SS_REL_P(rel,d_blob), *bbuf, mtype, size);
                 ss_blob_read1(SS_REL_P(rel,d_blob), (hsize_t)0, size, SS_BLOB_UNBIND, NULL);
             }
         }
     }

     if (mtype>0) H5Tclose(mtype);
     if (_SAF_GLOBALS.p.TraceTimes)
         _SAF_GLOBALS.CummReadTime += _saf_wall_clock(FALSE) - timer_start;

     SAF_LEAVE(SAF_SUCCESS);

 }