Beispiel #1
0
void *process(void *targ) {
  struct thread_data *tdata; 
  void *db,*rec,*lptr;
  wg_int encptr;
  int i,tid,ptrfld;
     
  tdata=(struct thread_data *) targ;    
  tid=tdata->thread_id;
  db=tdata->db;
  ptrfld=tdata->ptrfld;  
  rec=wg_decode_record(db,tdata->fptr);
  lptr=wg_decode_record(db,tdata->lptr);
  
  printf("thread %d starts, first el value %d \n",tid,
         wg_decode_int(db,wg_get_field(db,rec,1)));
  i=1;
  while(1) {
    encptr=*(wg_field_addr(db,rec,ptrfld)); // encptr is not yet decoded   
    rec=wg_decode_record(db,encptr); // get a pointer to the previous record
    if (rec==lptr) break;
    i++;    
  } 
  tdata->res=i; 
  printf ("thread %d finishing with res %d \n",tid,i);
  pthread_exit((void*) tid);
}
Beispiel #2
0
int main(int argc, char **argv) {
  void *db, *ctrl, *rec;
  char *name=DB_NAME;
  int i,ptrfld,ptrs,rc;  
  wg_int encptr,tmp,first,next,last;
  pthread_t threads[MAX_THREADS];   
  struct thread_data tdata[MAX_THREADS];
  pthread_attr_t attr;
  long tid;
  
  db = wg_attach_database(name, 1000000000);
  if (!db) { printf("db creation failed \n"); exit(0); }
  
  // get values from cntrl record
  ctrl=wg_get_first_record(db);  
  ptrfld=wg_decode_int(db,wg_get_field(db,ctrl,1));
  first=wg_get_field(db,ctrl,2);
  for(ptrs=0;ptrs<10000;ptrs++) {
    tmp=wg_get_field(db,ctrl,3+ptrs);
    if ((int)tmp==0) break;          
    last=tmp;
  }
  printf("\nsegments found: %d \n",ptrs);
  if (ptrs>=MAX_THREADS) {
    printf("List segment nr larger than MAX_THREADS, exiting\n");
    wg_detach_database(db);  
    pthread_exit(NULL);
    return 0;
  }
  // prepare and create threads
  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  
  for(tid=0;tid<ptrs;tid++) {   
    first=wg_get_field(db,ctrl,2+tid);
    next=wg_get_field(db,ctrl,2+tid+1);
    tdata[tid].thread_id=tid;
    tdata[tid].db=db;
    tdata[tid].fptr=first;
    tdata[tid].lptr=next;
    tdata[tid].ptrfld=ptrfld;
    tdata[tid].res=0;    
    rc=pthread_create(&threads[tid], &attr, process, (void *) &tdata[tid]);    
  }  

  // wait for all threads to finish
  for(tid=0;tid<ptrs;tid++) {
    pthread_join(threads[tid],NULL);
    //printf("thread %d finished with res %d\n",
    //        tdata[tid].thread_id,tdata[tid].res);
  }  
  printf("\nall threads finished\n"); 
  wg_detach_database(db);  
  pthread_exit(NULL);
  return 0;
}
Beispiel #3
0
/**
 * Check the database state
 */
void check_data(void *db, int wcnt) {
  void *rec = wg_get_first_record(db);
  int cksum;
  if(rec == NULL) {
    fprintf(stderr, "Database check failed: first record not found.\n");
    return;
  }
  cksum = wg_decode_int(db, wg_get_field(db, rec, 0));
  if(cksum != wcnt * WORKLOAD) {
    fprintf(stderr, "Database check failed: bad checksum (%d != %d).\n",
      cksum, wcnt * WORKLOAD);
    return;
  }
}
Beispiel #4
0
/** Compare two encoded values
 * a, b - encoded values
 * returns WG_GREATER, WG_EQUAL or WG_LESSTHAN
 * assumes that a and b themselves are not equal and so
 * their decoded values need to be examined (which could still
 * be equal for some data types).
 * depth - recursion depth for records
 */
gint wg_compare(void *db, gint a, gint b, int depth) {
/* a very simplistic version of the function:
 * - we get the types of the variables
 * - if the types match, compare the decoded values
 * - otherwise compare the type codes (not really scientific,
 *   but will provide a means of ordering values).
 *
 * One important point that should be observed here is
 * that the returned values should be consistent when
 * comparing A to B and then B to A. This applies to cases
 * where we have no reason to think one is greater than
 * the other from the *user's* point of view, but for use
 * in T-tree index and similar, values need to be consistently
 * ordered. Examples include unknown types and record pointers
 * (once recursion depth runs out).
 */

  /* XXX: might be able to save time here to mask and compare
   * the type bits instead */
  gint typea = wg_get_encoded_type(db, a);
  gint typeb = wg_get_encoded_type(db, b);

  /* assume types are >2 (NULLs are always equal) and
   * <13 (not implemented as of now)
   * XXX: all of this will fall apart if type codes
   * are somehow rearranged :-) */
  if(typeb==typea) {
    if(typea>WG_CHARTYPE) { /* > 9, not a string */
      if(typea>WG_FIXPOINTTYPE) {
        /* date or time. Compare decoded gints */
        gint deca, decb;
        if(typea==WG_DATETYPE) {
          deca = wg_decode_date(db, a);
          decb = wg_decode_date(db, b);
        } else if(typea==WG_TIMETYPE) {
          deca = wg_decode_time(db, a);
          decb = wg_decode_time(db, b);
        } else if(typea==WG_VARTYPE) {
          deca = wg_decode_var(db, a);
          decb = wg_decode_var(db, b);
        } else {
          /* anon const or other new type, no idea how to compare */
          return (a>b ? WG_GREATER : WG_LESSTHAN);
        }
        return (deca>decb ? WG_GREATER : WG_LESSTHAN);
      } else {
        /* fixpoint, need to compare doubles */
        double deca, decb;
        deca = wg_decode_fixpoint(db, a);
        decb = wg_decode_fixpoint(db, b);
        return (deca>decb ? WG_GREATER : WG_LESSTHAN);
      }
    }
    else if(typea<WG_STRTYPE) { /* < 5, still not a string */
      if(typea==WG_RECORDTYPE) {
        void *deca, *decb;
        deca = wg_decode_record(db, a);
        decb = wg_decode_record(db, b);

        if(!depth) {
          /* No more recursion allowed and pointers aren't equal.
           * So while we're technically comparing the addresses here,
           * the main point is that the returned value != WG_EQUAL
           */
          return ((gint) deca> (gint) decb ? WG_GREATER : WG_LESSTHAN);
        }
        else {
          int i;
#ifdef USE_CHILD_DB
          void *parenta, *parentb;
#endif
          int lena = wg_get_record_len(db, deca);
          int lenb = wg_get_record_len(db, decb);

#ifdef USE_CHILD_DB
          /* Determine, if the records are inside the memory area beloning
           * to our current base address. If it is outside, the encoded
           * values inside the record contain offsets in relation to
           * a different base address and need to be translated.
           */
          parenta = wg_get_rec_owner(db, deca);
          parentb = wg_get_rec_owner(db, decb);
#endif

          /* XXX: Currently we're considering records of differing lengths
           * non-equal without comparing the elements
           */
          if(lena!=lenb)
            return (lena>lenb ? WG_GREATER : WG_LESSTHAN);

          /* Recursively check each element in the record. If they
           * are not equal, break and return with the obtained value
           */
          for(i=0; i<lena; i++) {
            gint elema = wg_get_field(db, deca, i);
            gint elemb = wg_get_field(db, decb, i);

#ifdef USE_CHILD_DB
            if(parenta != dbmemseg(db)) {
              elema = wg_translate_hdroffset(db, parenta, elema);
            }
            if(parentb != dbmemseg(db)) {
              elemb = wg_translate_hdroffset(db, parentb, elemb);
            }
#endif

            if(elema != elemb) {
              gint cr = wg_compare(db, elema, elemb, depth - 1);
              if(cr != WG_EQUAL)
                return cr;
            }
          }
          return WG_EQUAL; /* all elements matched */
        }
      }
      else if(typea==WG_INTTYPE) {
        gint deca, decb;
        deca = wg_decode_int(db, a);
        decb = wg_decode_int(db, b);
        if(deca==decb) return WG_EQUAL; /* large ints can be equal */
        return (deca>decb ? WG_GREATER : WG_LESSTHAN);
      } else {
        /* WG_DOUBLETYPE */
        double deca, decb;
        deca = wg_decode_double(db, a);
        decb = wg_decode_double(db, b);
        if(deca==decb) return WG_EQUAL; /* decoded doubles can be equal */
        return (deca>decb ? WG_GREATER : WG_LESSTHAN);
      }
    }
    else { /* string */
      /* Need to compare the characters. In case of 0-terminated
       * strings we use strcmp() directly, which in glibc is heavily
       * optimised. In case of blob type we need to query the length
       * and use memcmp().
       */
      char *deca, *decb, *exa=NULL, *exb=NULL;
      char buf[4];
      gint res;
      if(typea==WG_STRTYPE) {
        /* lang is ignored */
        deca = wg_decode_str(db, a);
        decb = wg_decode_str(db, b);
      }
      else if(typea==WG_URITYPE) {
        exa = wg_decode_uri_prefix(db, a);
        exb = wg_decode_uri_prefix(db, b);
        deca = wg_decode_uri(db, a);
        decb = wg_decode_uri(db, b);
      }
      else if(typea==WG_XMLLITERALTYPE) {
        exa = wg_decode_xmlliteral_xsdtype(db, a);
        exb = wg_decode_xmlliteral_xsdtype(db, b);
        deca = wg_decode_xmlliteral(db, a);
        decb = wg_decode_xmlliteral(db, b);
      }
      else if(typea==WG_CHARTYPE) {
        buf[0] = wg_decode_char(db, a);
        buf[1] = '\0';
        buf[2] = wg_decode_char(db, b);
        buf[3] = '\0';
        deca = buf;
        decb = &buf[2];
      }
      else { /* WG_BLOBTYPE */
        deca = wg_decode_blob(db, a);
        decb = wg_decode_blob(db, b);
      }

      if(exa || exb) {
        /* String type where extra information is significant
         * (we're ignoring this for plain strings and blobs).
         * If extra part is equal, normal comparison continues. If
         * one string is missing altogether, it is considered to be
         * smaller than the other string.
         */
        if(!exb) {
          if(exa[0])
            return WG_GREATER;
        } else if(!exa) {
          if(exb[0])
            return WG_LESSTHAN;
        } else {
          res = strcmp(exa, exb);
          if(res > 0) return WG_GREATER;
          else if(res < 0) return WG_LESSTHAN;
        }
      }

#if 0 /* paranoia check */
      if(!deca || !decb) {
        if(decb)
          if(decb[0])
            return WG_LESSTHAN;
        } else if(deca) {
          if(deca[0])
            return WG_GREATER;
        }
        return WG_EQUAL;
      }
#endif

      if(typea==WG_BLOBTYPE) {
        /* Blobs are not 0-terminated */
        int lena = wg_decode_blob_len(db, a);
        int lenb = wg_decode_blob_len(db, b);
        res = memcmp(deca, decb, (lena < lenb ? lena : lenb));
        if(!res) res = lena - lenb;
      } else {
        res = strcmp(deca, decb);
      }
      if(res > 0) return WG_GREATER;
      else if(res < 0) return WG_LESSTHAN;
      else return WG_EQUAL;
    }
  }
Beispiel #5
0
void run_demo(void* db) {
  void *rec = NULL, *firstrec = NULL, *nextrec = NULL;
                                /* Pointers to a database record */
  wg_int enc; /* Encoded data */
  wg_int lock_id; /* Id of an acquired lock (for releasing it later) */
  wg_int len;
  int i;
  int intdata, datedata, timedata;
  char strbuf[80];

  printf("********* Starting demo ************\n");

  /* Begin by creating a simple record of 3 fields and fill it
   * with integer data.
   */

  printf("Creating first record.\n");

  rec=wg_create_record(db, 3);
  if (rec==NULL) {
    printf("rec creation error.\n");
    return;
  }

  /* Encode a field, checking for errors */
  enc = wg_encode_int(db, 44);
  if(enc==WG_ILLEGAL) {
    printf("failed to encode an integer.\n");
    return;
  }

  /* Negative return value shows that an error occurred */
  if(wg_set_field(db, rec, 0, enc) < 0) {
    printf("failed to store a field.\n");
    return;
  }
  
  /* Skip error checking for the sake of brevity for the rest of fields */
  enc = wg_encode_int(db, -199999);
  wg_set_field(db, rec, 1, enc);
  wg_set_field(db, rec, 2, wg_encode_int(db, 0));

  /* Now examine the record we have created. Get record length,
   * encoded value of each field, data type and decoded value.
   */

  /* Negative return value shows an error. */
  len = wg_get_record_len(db, rec);
  if(len < 0) {
    printf("failed to get record length.\n");
    return;
  }
  printf("Size of created record at %p was: %d\n", rec, (int) len);

  for(i=0; i<len; i++) {
    printf("Reading field %d:", i);
    enc = wg_get_field(db, rec, i);
    if(wg_get_encoded_type(db, enc) != WG_INTTYPE) {
      printf("data was of unexpected type.\n");
      return;
    }
    intdata = wg_decode_int(db, enc);
    /* No error checking here. All integers are valid. */
    printf(" %d\n", intdata);
  }

  /* Fields can be erased by setting their value to 0 which always stands for NULL value. */
  printf("Clearing field 1.\n");
  
  wg_set_field(db, rec, 1, 0);

  if(wg_get_field(db, rec, 1)==0) {
    printf("Re-reading field 1 returned a 0 (NULL) field.\n");
  } else {
    printf("unexpected value \n");
    return;
  }

  /* Fields can be updated with data of any type (the type is not fixed). */
  printf("Updating field 0 to a floating-point number.\n");

  enc = wg_encode_double(db, 56.9988);
  wg_set_field(db, rec, 0, enc);
  
  enc = wg_get_field(db, rec, 0);
  if(wg_get_encoded_type(db, enc) == WG_DOUBLETYPE) {
    printf("Re-reading field 0 returned %f.\n", wg_decode_double(db, enc));
  } else {
    printf("data was of unexpected type.\n");
    return;
  }

  /* Create a next record. Let's assume we're in an environment where
   * the database is used concurrently, so there's a need to use locking.
   */

  printf("Creating second record.\n");

  /* Lock id of 0 means that the operation failed */
  lock_id = wg_start_write(db);
  if(!lock_id) {
    printf("failed to acquire lock.\n");
    return;
  }
    
  /* Do the write operation we acquired the lock for. */
  rec=wg_create_record(db, 6);
  
  /* Failing to release the lock would be fatal to database operation. */
  if(!wg_end_write(db, lock_id)) {
    printf("failed to release lock.\n");
    return;
  }

  if (!rec) {
    printf("rec creation error.\n");
    return;
  }

  /* Reading also requires locking./ */
  lock_id = wg_start_read(db);
  if(!lock_id) {
    printf("failed to acquire lock.\n");
    return;
  }

  /* Do our read operation... */
  len = wg_get_record_len(db, rec);

  /* ... and unlock immediately */
  if(!wg_end_read(db, lock_id)) {
    printf("failed to release lock.\n");
    return;
  }

  if(len < 0) {
    printf("failed to get record length.\n");
    return;
  }
  printf("Size of created record at %p was: %d\n", rec, (int) len);

  /* Let's find the first record in the database */
  lock_id = wg_start_read(db);
  firstrec = wg_get_first_record(db);
  wg_end_read(db, lock_id);
  if(!firstrec) {
    printf("Failed to find first record.\n");
    return;
  }

  printf("First record of database had address %p.\n", firstrec);
  
  /* Let's check what the next record is to demonstrate scanning records. */
  nextrec = firstrec;
  lock_id = wg_start_read(db);
  do {
    
    nextrec = wg_get_next_record(db, nextrec);
    if(nextrec)
      printf("Next record had address %p.\n", nextrec);   
  } while(nextrec);
  printf("Finished scanning database records.\n");
  wg_end_read(db, lock_id);
  
  /* Set fields to various values. Field 0 is not touched at all (un-
   * initialized). Field 1 is set to point to another record.
   */

  printf("Populating second record with data.\n");

  /* Let's use the first record we found to demonstrate storing
   * a link to a record in a field inside another record. */
  lock_id = wg_start_write(db);
  enc = wg_encode_record(db, firstrec);
  wg_set_field(db, rec, 1, enc);
  wg_end_write(db, lock_id);

  /* Now set other fields to various data types. To keep the example shorter,
   * the locking and unlocking operations are omitted (in real applications,
   * this would be incorrect usage if concurrent access is expected).
   */

  wg_set_field(db, rec, 2, wg_encode_str(db, "This is a char array", NULL));
  wg_set_field(db, rec, 3, wg_encode_char(db, 'a'));

  /* For time and date, we use current time in local timezone */
  enc = wg_encode_date(db, wg_current_localdate(db));
  if(enc==WG_ILLEGAL) {
    printf("failed to encode date.\n");
    return;
  }
  wg_set_field(db, rec, 4, enc);

  enc = wg_encode_time(db, wg_current_localtime(db));
  if(enc==WG_ILLEGAL) {
    printf("failed to encode time.\n");
    return;
  }
  wg_set_field(db, rec, 5, enc);

  /* Now read and print all the fields. */
  
  wg_print_record(db, (wg_int *) rec);   
  printf("\n");

  /* Date and time can be handled together as a datetime object. */
  datedata = wg_decode_date(db, wg_get_field(db, rec, 4));
  timedata = wg_decode_time(db, wg_get_field(db, rec, 5));
  wg_strf_iso_datetime(db, datedata, timedata, strbuf);
  printf("Reading datetime: %s.\n", strbuf);
  
  printf("Setting date and time to 2010-03-31, 12:59\n");

  /* Update date and time to arbitrary values using wg_strp_iso_date/time */
  wg_set_field(db, rec, 4,
    wg_encode_date(db, wg_strp_iso_date(db, "2010-03-31")));
  wg_set_field(db, rec, 5,
    wg_encode_time(db, wg_strp_iso_time(db, "12:59:00.33")));

  printf("Dumping the contents of the database:\n");
  wg_print_db(db);

  printf("********* Demo ended ************\n");
}
Beispiel #6
0
char* sprint_value(void *db, wg_int enc, char **buf, int *bufsize, char **bptr,
                 int format, int showid, int depth, int maxdepth, int strenc) {
  wg_int *ptrdata;
  int intdata,strl,strl1,strl2;
  char *strdata, *exdata;
  double doubledata;
  char strbuf[80]; // tmp area for dates
  int limit=MIN_STRLEN;

  switch(wg_get_encoded_type(db, enc)) {
    case WG_NULLTYPE:
      str_guarantee_space(buf, bufsize, bptr, MIN_STRLEN);
      if (format!=0) {
        // json
        snprintf(*bptr, limit, JS_NULL);
        return *bptr+strlen(*bptr);
      }
      return *bptr;
    case WG_RECORDTYPE:
      str_guarantee_space(buf, bufsize, bptr, MIN_STRLEN);
      if (!format || depth>=maxdepth) {
        snprintf(*bptr, limit,"%d", (int)enc); // record offset (i.e. id)
        return *bptr+strlen(*bptr);
      } else {
        // recursive print
        ptrdata = wg_decode_record(db, enc);
        sprint_record(db,ptrdata,buf,bufsize,bptr,format,showid,depth+1,maxdepth,strenc);
        **bptr='\0';
        return *bptr;
      }
      break;
    case WG_INTTYPE:
      intdata = wg_decode_int(db, enc);
      str_guarantee_space(buf, bufsize, bptr, MIN_STRLEN);
      snprintf(*bptr, limit, "%d", intdata);
      return *bptr+strlen(*bptr);
    case WG_DOUBLETYPE:
      doubledata = wg_decode_double(db, enc);
      str_guarantee_space(buf, bufsize, bptr, MIN_STRLEN);
      snprintf(*bptr, limit, DOUBLE_FORMAT, doubledata);
      return *bptr+strlen(*bptr);
    case WG_FIXPOINTTYPE:
      doubledata = wg_decode_fixpoint(db, enc);
      str_guarantee_space(buf, bufsize, bptr, MIN_STRLEN);
      snprintf(*bptr, limit, DOUBLE_FORMAT, doubledata);
      return *bptr+strlen(*bptr);
    case WG_STRTYPE:
      strdata = wg_decode_str(db, enc);
      exdata = wg_decode_str_lang(db,enc);
      if (strdata!=NULL) strl1=strlen(strdata);
      else strl1=0;
      if (exdata!=NULL) strl2=strlen(exdata);
      else strl2=0;
      str_guarantee_space(buf, bufsize, bptr, MIN_STRLEN+STRLEN_FACTOR*(strl1+strl2));
      sprint_string(*bptr,(strl1+strl2),strdata,strenc);
      if (exdata!=NULL) {
        snprintf(*bptr+strl1+1,limit,"@%s\"", exdata);
      }
      return *bptr+strlen(*bptr);
    case WG_URITYPE:
      strdata = wg_decode_uri(db, enc);
      exdata = wg_decode_uri_prefix(db, enc);
      if (strdata!=NULL) strl1=strlen(strdata);
      else strl1=0;
      if (exdata!=NULL) strl2=strlen(exdata);
      else strl2=0;
      limit=MIN_STRLEN+STRLEN_FACTOR*(strl1+strl2);
      str_guarantee_space(buf, bufsize, bptr, limit);
      if (exdata==NULL)
        snprintf(*bptr, limit, "\"%s\"", strdata);
      else
        snprintf(*bptr, limit, "\"%s:%s\"", exdata, strdata);
      return *bptr+strlen(*bptr);
    case WG_XMLLITERALTYPE:
      strdata = wg_decode_xmlliteral(db, enc);
      exdata = wg_decode_xmlliteral_xsdtype(db, enc);
      if (strdata!=NULL) strl1=strlen(strdata);
      else strl1=0;
      if (exdata!=NULL) strl2=strlen(exdata);
      else strl2=0;
      limit=MIN_STRLEN+STRLEN_FACTOR*(strl1+strl2);
      str_guarantee_space(buf, bufsize, bptr, limit);
      snprintf(*bptr, limit, "\"%s:%s\"", exdata, strdata);
      return *bptr+strlen(*bptr);
    case WG_CHARTYPE:
      intdata = wg_decode_char(db, enc);
      str_guarantee_space(buf, bufsize, bptr, MIN_STRLEN);
      snprintf(*bptr, limit, "\"%c\"", (char) intdata);
      return *bptr+strlen(*bptr);
    case WG_DATETYPE:
      intdata = wg_decode_date(db, enc);
      wg_strf_iso_datetime(db,intdata,0,strbuf);
      strbuf[10]=0;
      str_guarantee_space(buf, bufsize, bptr, MIN_STRLEN);
      snprintf(*bptr, limit, "\"%s\"",strbuf);
      return *bptr+strlen(*bptr);
    case WG_TIMETYPE:
      intdata = wg_decode_time(db, enc);
      wg_strf_iso_datetime(db,1,intdata,strbuf);
      str_guarantee_space(buf, bufsize, bptr, MIN_STRLEN);
      snprintf(*bptr, limit, "\"%s\"",strbuf+11);
      return *bptr+strlen(*bptr);
    case WG_VARTYPE:
      intdata = wg_decode_var(db, enc);
      str_guarantee_space(buf, bufsize, bptr, MIN_STRLEN);
      snprintf(*bptr, limit, "\"?%d\"", intdata);
      return *bptr+strlen(*bptr);
    case WG_BLOBTYPE:
      strdata = wg_decode_blob(db, enc);
      strl=wg_decode_blob_len(db, enc);
      limit=MIN_STRLEN+STRLEN_FACTOR*strlen(strdata);
      str_guarantee_space(buf, bufsize, bptr, limit);
      sprint_blob(*bptr,strl,strdata,strenc);
      return *bptr+strlen(*bptr);
    default:
      str_guarantee_space(buf, bufsize, bptr, MIN_STRLEN);
      snprintf(*bptr, limit, JS_TYPE_ERR);
      return *bptr+strlen(*bptr);
  }
}
Beispiel #7
0
void run_workers(void *db, int rcnt, int wcnt) {
  pt_data *pt_table;
  int i, tcnt;
#ifdef HAVE_PTHREAD
  int err;
  void *status;
  pthread_attr_t attr;
#endif

#if !defined(HAVE_PTHREAD) && !defined(_WIN32)
  fprintf(stderr, "No thread support: skipping tests.\n");
  return;
#endif

#ifdef HAVE_PTHREAD
  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
#endif

#if defined(BENCHMARK) && defined(HAVE_PTHREAD)
  pthread_rwlock_init(&rwlock, NULL);
#endif

#ifdef SYNC_THREADS
#if defined(HAVE_PTHREAD)
  pthread_mutex_init(&twait_mutex, NULL);
  pthread_cond_init(&twait_cv, NULL);
#elif defined(_WIN32)
  /* Manual reset event, initial state nonsignaled. */
  twait_ev = CreateEvent(NULL, TRUE, FALSE, NULL);
#endif
#endif

  tcnt = rcnt + wcnt;
  pt_table = (pt_data *) malloc(tcnt * sizeof(pt_data));
  if(!pt_table) {
    fprintf(stderr, "Failed to allocate thread table: skipping tests.\n");
    return;
  }

  /* Spawn the threads */
#ifdef SYNC_THREADS
  twait_cnt = 0;
#endif
  for(i=0; i<tcnt; i++) {
    pt_table[i].db = db;
    pt_table[i].threadid = i;

    /* First wcnt threads are writers, the remainder readers */
    if(i<wcnt) {
#if defined(HAVE_PTHREAD)
      err = pthread_create(&pt_table[i].pth, &attr, writer_thread, \
        (void *) &pt_table[i]);
#elif defined(_WIN32)
      pt_table[i].hThread = CreateThread(NULL, 0,
        (LPTHREAD_START_ROUTINE) writer_thread,
        (LPVOID) &pt_table[i], 0, NULL);
#endif
    } else {
#if defined(HAVE_PTHREAD)
      err = pthread_create(&pt_table[i].pth, &attr, reader_thread, \
        (void *) &pt_table[i]);
#elif defined(_WIN32)
      pt_table[i].hThread = CreateThread(NULL, 0,
        (LPTHREAD_START_ROUTINE) reader_thread,
        (LPVOID) &pt_table[i], 0, NULL);
#endif
    }

#if defined(HAVE_PTHREAD)
    if(err) {
      fprintf(stderr, "Error code from pthread_create: %d.\n", err);
#elif defined(_WIN32)
    if(!pt_table[i].hThread) {
      /* XXX: GetLastError() gives the error code if needed */
      fprintf(stderr, "CreateThread failed.\n");
#endif
      goto workers_done;
    }
  }

#ifdef SYNC_THREADS
  /* Check that all workers have entered wait state */
  for(;;) {
    /* While reading a word from memory is atomic, we
     * still use the mutex because we want to guarantee
     * that the last thread has called pthread_cond_wait().
     * With Win32 API, condition variables with similar
     * functionality are available starting from Windows Vista,
     * so this implementation uses a simple synchronization
     * event instead. This causes small, probably non-relevant
     * loss in sync accuracy.
     */
#ifdef HAVE_PTHREAD
    pthread_mutex_lock(&twait_mutex);
#endif
    if(twait_cnt >= tcnt) break;
#ifdef HAVE_PTHREAD
    pthread_mutex_unlock(&twait_mutex);
#endif
  }

  /* Now wake up all threads */
#if defined(HAVE_PTHREAD)
  pthread_cond_broadcast(&twait_cv);
  pthread_mutex_unlock(&twait_mutex);
#elif defined(_WIN32)
  SetEvent(twait_ev);
#endif
#endif /* SYNC_THREADS */

  /* Join the workers (wait for them to complete) */
  for(i=0; i<tcnt; i++) {
#if defined(HAVE_PTHREAD)
    err = pthread_join(pt_table[i].pth, &status);
    if(err) {
      fprintf(stderr, "Error code from pthread_join: %d.\n", err);
      break;
    }
#elif defined(_WIN32)
    WaitForSingleObject(pt_table[i].hThread, INFINITE);
    CloseHandle(pt_table[i].hThread);
#endif
  }

workers_done:
#ifdef HAVE_PTHREAD
  pthread_attr_destroy(&attr);
#endif

#if defined(BENCHMARK) && defined(HAVE_PTHREAD)
  pthread_rwlock_destroy(&rwlock);
#endif

#ifdef SYNC_THREADS
#if defined(HAVE_PTHREAD)
  pthread_mutex_destroy(&twait_mutex);
  pthread_cond_destroy(&twait_cv);
#elif defined(_WIN32)
  CloseHandle(twait_ev);
#endif
#endif
  free(pt_table);
}

/** Writer thread
 *  Runs preconfigured number of basic write transactions
 */

worker_t writer_thread(void * threadarg) {
  void * db;
  int threadid, i, j, cksum;
  void *rec = NULL, *frec = NULL;

  db = ((pt_data *) threadarg)->db;
  threadid = ((pt_data *) threadarg)->threadid;

#ifdef CHATTY_THREADS
  fprintf(stdout, "Writer thread %d started.\n", threadid);
#endif

#ifdef SYNC_THREADS
  /* Increment the thread counter to inform the caller
   * that we are entering wait state.
   */
#ifdef HAVE_PTHREAD
  pthread_mutex_lock(&twait_mutex);
#endif
  twait_cnt++;
#if defined(HAVE_PTHREAD)
  pthread_cond_wait(&twait_cv, &twait_mutex);
  pthread_mutex_unlock(&twait_mutex);
#elif defined(_WIN32)
  WaitForSingleObject(twait_ev, INFINITE);
#endif
#endif /* SYNC_THREADS */

  frec = wg_get_first_record(db);
  for(i=0; i<WORKLOAD; i++) {
    wg_int c=-1, lock_id;

#if defined(BENCHMARK) && defined(HAVE_PTHREAD)
    pthread_rwlock_wrlock(&rwlock);
#else
    /* Start transaction */
    if(!(lock_id = wg_start_write(db))) {
      fprintf(stderr, "Writer thread %d: wg_start_write failed.\n", threadid);
      goto writer_done;
    }
#endif

    /* Fetch checksum */
    cksum = wg_decode_int(db, wg_get_field(db, frec, 0));

    /* Fetch record from database */
    if(i) rec = wg_get_next_record(db, rec);
    else rec = frec;
    if(!rec) {
      fprintf(stderr, "Writer thread %d: wg_get_next_record failed.\n", threadid);
#if defined(BENCHMARK) && defined(HAVE_PTHREAD)
      pthread_rwlock_unlock(&rwlock);
#else
      wg_end_write(db, lock_id);
#endif
      goto writer_done;
    }

    /* Modify record */
    if(i) j = 0;
    else j = 1;
    for(; j<REC_SIZE; j++) {
      if (wg_set_int_field(db, rec, j, c--) != 0) {
        fprintf(stderr, "Writer thread %d: int storage error.\n", threadid);
#if defined(BENCHMARK) && defined(HAVE_PTHREAD)
        pthread_rwlock_unlock(&rwlock);
#else
        wg_end_write(db, lock_id);
#endif
        goto writer_done;
      }
    }

    /* Update checksum */
    wg_set_int_field(db, frec, 0, ++cksum);

#if defined(BENCHMARK) && defined(HAVE_PTHREAD)
    pthread_rwlock_unlock(&rwlock);
#else
    /* End transaction */
    if(!wg_end_write(db, lock_id)) {
      fprintf(stderr, "Writer thread %d: wg_end_write failed.\n", threadid);
      goto writer_done;
    }
#endif
  }

#ifdef CHATTY_THREADS
  fprintf(stdout, "Writer thread %d ended.\n", threadid);
#endif

writer_done:
#if defined(HAVE_PTHREAD)
  pthread_exit(NULL);
#elif defined(_WIN32)
  return 0;
#endif
}
Beispiel #8
0
/*
 * Return an encoded value as a decoded byte array.
 * It should be freed afterwards.
 * returns the number of bytes in the array.
 * returns 0 if the decode failed.
 *
 * NOTE: to differentiate between identical byte strings
 * the value is prefixed with a type identifier.
 * TODO: For values with varying length that can contain
 * '\0' bytes, add length to the prefix.
 */
gint wg_decode_for_hashing(void *db, gint enc, char **decbytes) {
  gint len;
  gint type;
  gint ptrdata;
  int intdata;
  double doubledata;
  char *bytedata;
  char *exdata, *buf = NULL, *outbuf;

  type = wg_get_encoded_type(db, enc);
  switch(type) {
    case WG_NULLTYPE:
      len = sizeof(gint);
      ptrdata = 0;
      bytedata = (char *) &ptrdata;
      break;
    case WG_RECORDTYPE:
      len = sizeof(gint);
      ptrdata = enc;
      bytedata = (char *) &ptrdata;
      break;
    case WG_INTTYPE:
      len = sizeof(int);
      intdata = wg_decode_int(db, enc);
      bytedata = (char *) &intdata;
      break;
    case WG_DOUBLETYPE:
      len = sizeof(double);
      doubledata = wg_decode_double(db, enc);
      bytedata = (char *) &doubledata;
      break;
    case WG_FIXPOINTTYPE:
      len = sizeof(double);
      doubledata = wg_decode_fixpoint(db, enc);
      bytedata = (char *) &doubledata;
      break;
    case WG_STRTYPE:
      len = wg_decode_str_len(db, enc);
      bytedata = wg_decode_str(db, enc);
      break;
    case WG_URITYPE:
      len = wg_decode_uri_len(db, enc);
      bytedata = wg_decode_uri(db, enc);
      exdata = wg_decode_uri_prefix(db, enc);
      CONCAT_FOR_HASHING(db, bytedata, exdata, len, buf, enc)
      break;
    case WG_XMLLITERALTYPE:
      len = wg_decode_xmlliteral_len(db, enc);
      bytedata = wg_decode_xmlliteral(db, enc);
      exdata = wg_decode_xmlliteral_xsdtype(db, enc);
      CONCAT_FOR_HASHING(db, bytedata, exdata, len, buf, enc)
      break;
    case WG_CHARTYPE:
      len = sizeof(int);
      intdata = wg_decode_char(db, enc);
      bytedata = (char *) &intdata;
      break;
    case WG_DATETYPE:
      len = sizeof(int);
      intdata = wg_decode_date(db, enc);
      bytedata = (char *) &intdata;
      break;
    case WG_TIMETYPE:
      len = sizeof(int);
      intdata = wg_decode_time(db, enc);
      bytedata = (char *) &intdata;
      break;
    case WG_VARTYPE:
      len = sizeof(int);
      intdata = wg_decode_var(db, enc);
      bytedata = (char *) &intdata;
      break;
    case WG_ANONCONSTTYPE:
      /* Ignore anonconst */
    default:
      return 0;
  }

  /* Form the hashable buffer. It is not 0-terminated */
  outbuf = malloc(len + 1);
  if(outbuf) {
    outbuf[0] = (char) type;
    memcpy(outbuf + 1, bytedata, len++);
    *decbytes = outbuf;
  } else {
    /* Indicate failure */
    len = 0;
  }

  if(buf)
    free(buf);
  return len;
}