Beispiel #1
0
/** Delete rows
 *  Like query(), except the selected rows are deleted.
 */
void del(void *db, char **argv, int argc) {
  int qargc;
  void *rec = NULL;
  wg_query *q;
  wg_query_arg *arglist;
  gint lock_id;

  arglist = make_arglist(db, argv, argc, &qargc);
  if(!arglist)
    return;

  /* Use maximum isolation */
  if(!(lock_id = wg_start_write(db))) {
    fprintf(stderr, "failed to get lock on database\n");
    goto abrt1;
  }

  q = wg_make_query(db, NULL, 0, arglist, qargc);
  if(!q)
    goto abrt2;

  if(q->res_count > 0) {
    printf("Deleting %d rows...", (int) q->res_count);
    rec = wg_fetch(db, q);
    while(rec) {
      wg_delete_record(db, (gint *) rec);
      rec = wg_fetch(db, q);
    }
    printf(" done\n");
  }

  wg_free_query(db, q);
abrt2:
  wg_end_write(db, lock_id);
abrt1:
  free_arglist(db, arglist, qargc);
}
Beispiel #2
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 #3
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 #4
0
static char* insert(thread_data_p tdata, char* inparams[], char* invalues[], int incount) {
  char* database=tdata->database;
  char *token=NULL;
  int i,tmp;
  //int j,x;
  char* json=NULL;
  //int count=MAXCOUNT;
  void* db=NULL; // actual database pointer
  //void* rec; 
  char* res;
  wg_int lock_id=0;  // non-0 iff lock set  
  char errbuf[ERRBUF_LEN]; // used for building variable-content input param error strings only
  
  // yajl
  /*
  yajl_handle hand;
  yajl_gen g;  
  yajl_status stat;  
  size_t rd;  
  int retval = 0;  
  int a = 1;  
  */
  
  // -------check and parse cgi parameters, attach database ------------
  
  // set printing params to defaults
  tdata->format=1; // 1: json
  tdata->maxdepth=MAX_DEPTH_DEFAULT; // rec depth limit for printer
  tdata->showid=0; // add record id as first extra elem: 0: no, 1: yes
  tdata->strenc=2; // string special chars escaping:  0: just ", 1: urlencode, 2: json, 3: csv
  // find ids and display format parameters
  for(i=0;i<incount;i++) {
    if (strncmp(inparams[i],"rec",MAXQUERYLEN)==0) {
      json=invalues[i];   
    } else {  
      // handle generic parameters for all queries: at end of param check
      res=handle_generic_param(tdata,inparams[i],invalues[i],&token,errbuf);      
      if (res!=NULL) return res;  // return error string
    }    
  }
  if (json==NULL || strlen(json)==0) {
    return errhalt(MISSING_JSON_ERR,tdata);
  }
  // authorization
  if (!authorize(WRITE_LEVEL,tdata,database,token)) {
    return errhalt(NOT_AUTHORIZED_ERR,tdata);
  }  
  // all parameters and values were understood
  if (tdata->format==0) {
    // csv     
    tdata->maxdepth=0; // record structure not printed for csv
    tdata->strenc=3; // only " replaced with ""
  }  
  // attach to database
  db=op_attach_database(tdata,database,READ_LEVEL);
  if (!db) {
    if (!authorize(ADMIN_LEVEL,tdata,database,token)) {
      return errhalt(NOT_AUTHORIZED_INSERT_CREATE_ERR,tdata);
    } else { 
      if (tdata->realthread && tdata->common->shutdown) return NULL; // for multithreading only     
      db=op_create_database(tdata,database,0);
      if (!db) return err_clear_detach_halt(DB_CREATE_ERR,tdata);   
    }  
  }  
  // database attached OK
  // create output string buffer (may be reallocated later)
  tdata->buf=str_new(INITIAL_MALLOC);
  if (tdata->buf==NULL) return errhalt(MALLOC_ERR,tdata);
  tdata->bufsize=INITIAL_MALLOC;
  tdata->bufptr=tdata->buf;
  op_print_data_start(tdata,1);  
  
  // initialize yajl
  /*
  g = yajl_gen_alloc(NULL);  
  yajl_gen_config(g, yajl_gen_beautify, 0);  
  yajl_gen_config(g, yajl_gen_validate_utf8, 1);   
  hand = yajl_alloc(&callbacks, NULL, (void *) g);  
  yajl_config(hand, yajl_allow_comments, 1);  
  */
  
  // take a write lock
  if (tdata->realthread && tdata->common->shutdown) return NULL; // for multithreading only
  lock_id = wg_start_write(db); // get write lock
  tdata->lock_id=lock_id;
  tdata->lock_type=WRITE_LOCK_TYPE;
  if (!lock_id) return err_clear_detach_halt(LOCK_ERR,tdata);  
  
  // start parsing
  /*
  rd=strlen(json);  
  stat = yajl_parse(hand, json, rd);  
  if (stat==yajl_status_ok) stat=yajl_complete_parse(hand);    
  if (stat != yajl_status_ok) {  
    unsigned char * str = yajl_get_error(hand, 1, json, rd);  
    fprintf(stderr, "%s", (const char *) str);  
    yajl_free_error(hand, str);  
    retval = 1;  
  } else {
    // parse succeeded
    const unsigned char * buf;  
    size_t len;  
    yajl_gen_get_buf(g, &buf, &len);  
    fwrite(buf, 1, len, stdout);  
    yajl_gen_clear(g); 
  }    
  yajl_gen_free(g);  
  yajl_free(hand);
  */
  // parsing ended

  // parse json and insert
  tmp=wg_parse_json_document(db,json);
  if(tmp==-1) {
    return err_clear_detach_halt(JSON_ERR,tdata);
  } else if(tmp==-2) {
    return err_clear_detach_halt(INCONSISTENT_ERR,tdata);
  }
  if(!str_guarantee_space(tdata,MIN_STRLEN)) 
      return err_clear_detach_halt(MALLOC_ERR,tdata);
  strcpy(tdata->bufptr,"1");
  tdata->bufptr+=strlen("1");
  // end activity
  if (!wg_end_write(db, lock_id)) {  // release write lock
    return err_clear_detach_halt(LOCK_RELEASE_ERR,tdata);
  }
  tdata->lock_id=0;
  op_detach_database(tdata,db); 
  if(!op_print_data_end(tdata,1))
    return err_clear_detach_halt(MALLOC_ERR,tdata);    
  return tdata->buf;
}
Beispiel #5
0
static char* drop(thread_data_p tdata, char* inparams[], char* invalues[], int incount) {
  char* database=tdata->database;
  char *token=NULL;
  int i,tmp;
  void* db=NULL; // actual database pointer
  char *res;
  int lock_id=0;
  int found=0;
  char errbuf[ERRBUF_LEN];  
  
  // find and check parameters
  for(i=0;i<incount;i++) {
    if (strncmp(inparams[i],"db",MAXQUERYLEN)==0) {
      database=invalues[i];
      if(database==NULL || strlen(database)<1 || atoi(database)<=0) {
        return errhalt(DB_NAME_ERR,tdata);
      }
    } else {  
      // handle generic parameters for all queries: at end of param check
      res=handle_generic_param(tdata,inparams[i],invalues[i],&token,errbuf);      
      if (res!=NULL) return res;  // return error string
    }    
  }  
  // authorization
  if (!authorize(ADMIN_LEVEL,tdata,database,token)) {
    return errhalt(NOT_AUTHORIZED_ERR,tdata);
  }  
  // all parameters and values were understood
  // create output string buffer (may be reallocated later)
  tdata->buf=str_new(INITIAL_MALLOC);
  if (tdata->buf==NULL) return errhalt(MALLOC_ERR,tdata);
  tdata->bufsize=INITIAL_MALLOC;
  tdata->bufptr=tdata->buf;
  op_print_data_start(tdata,0);
  // check if access allowed in the conf file
  if (database!=NULL && (tdata->global)->conf->dbases.used>0) {
    for(i=0;i<(tdata->global)->conf->dbases.used;i++) {
      if (!strcmp(database,(tdata->global)->conf->dbases.vals[i])) {
        found=1;
        break;
      }
    }
    if (!found) return errhalt(DB_AUTHORIZE_ERR,tdata);
  }
  // first try to attach to an existing database 
  db=op_attach_database(tdata,database,ADMIN_LEVEL);
  if (db==NULL) {
    return errhalt(DB_NOT_EXISTS_ERR,tdata);
  } else {  
    // database exists, take lock
    if (tdata->realthread && tdata->common->shutdown) return NULL; // for multithreading only
    tdata->db=db;
    lock_id = wg_start_write(db); // get write lock
    tdata->lock_id=lock_id;
    tdata->lock_type=WRITE_LOCK_TYPE;
    if (!lock_id) return err_clear_detach_halt(LOCK_ERR,tdata); 
    tmp=wg_detach_database(db); // detaches a database: returns 0 if OK
    if (tmp) return err_clear_detach_halt(DB_DROP_ERR,tdata);
    tmp=wg_delete_database(database);    
    if (tmp) return errhalt(DB_DROP_ERR,tdata);
  }  
  // deleted successfully 
  tdata->db=NULL;
  tdata->lock_id=0;
  if(!str_guarantee_space(tdata,MIN_STRLEN)) 
      return err_clear_detach_halt(MALLOC_ERR,tdata);
  strcpy(tdata->bufptr,"1");
  tdata->bufptr+=strlen("1");
  // end activity
  if(!op_print_data_end(tdata,0))
    return errhalt(MALLOC_ERR,tdata);    
  return tdata->buf;
}