diff audioDB.cpp @ 498:342822c2d49a

Merge api-inversion branch (-r656:771, but I don't expect to return to that branch) into the trunk. I expect there to be minor performance regressions (e.g. in the SOAP server index cacheing, which I have forcibly removed) and minor unplugged memory leaks (e.g. in audioDB::query(), where I don't free up the datum). I hope that these leaks and performance regressions can be plugged in short order. I also expect that some (but maybe not all) of the issues currently addressed in the memory-leaks branch are superseded or fixed by this merge. There remains much work to be done; go forth and do it.
author mas01cr
date Sat, 10 Jan 2009 16:47:57 +0000
parents f9d86b1db21c
children da4b76190d43
line wrap: on
line diff
--- a/audioDB.cpp	Sat Jan 10 11:11:27 2009 +0000
+++ b/audioDB.cpp	Sat Jan 10 16:47:57 2009 +0000
@@ -1,27 +1,13 @@
 #include "audioDB.h"
+extern "C" {
+#include "audioDB_API.h"
+#include "audioDB-internals.h"
+}
+#include "reporter.h"
 
-LSH* SERVER_LSH_INDEX_SINGLETON;
 char* SERVER_ADB_ROOT;
 char* SERVER_ADB_FEATURE_ROOT;
 
-PointPair::PointPair(Uns32T a, Uns32T b, Uns32T c):trackID(a),qpos(b),spos(c){};
-
-bool operator<(const PointPair& a, const PointPair& b){
-  return ( (a.trackID<b.trackID) ||
-	   ( (a.trackID==b.trackID) &&  
-	     ( (a.spos<b.spos) || ( (a.spos==b.spos) && (a.qpos < b.qpos) )) ) );
-}
-
-bool operator>(const PointPair& a, const PointPair& b){
-  return ( (a.trackID>b.trackID) ||
-	   ( (a.trackID==b.trackID) &&  
-	     ( (a.spos>b.spos) || ( (a.spos==b.spos) && (a.qpos > b.qpos) )) ) );
-}
-
-bool operator==(const PointPair& a, const PointPair& b){
-  return ( (a.trackID==b.trackID) && (a.qpos==b.qpos) && (a.spos==b.spos) );
-}
-
 audioDB::audioDB(const unsigned argc, const char *argv[]): O2_AUDIODB_INITIALIZERS
 {
   if(processArgs(argc, argv)<0){
@@ -41,13 +27,7 @@
     prefix_name((char** const)&dbName, adb_root);
 
   if(O2_ACTION(COM_SERVER)){
-#ifdef LIBRARY
-    ;
-#else
     startServer();
-    if(SERVER_LSH_INDEX_SINGLETON)
-      delete lsh;
-#endif
   }
   else  if(O2_ACTION(COM_CREATE))
     create(dbName);
@@ -60,9 +40,6 @@
 
   else if(O2_ACTION(COM_QUERY))
     if(isClient){
-#ifdef LIBRARY
-      ;
-#else
       if(query_from_key){
 	VERB_LOG(1, "Calling web services query %s on database %s, query=%s\n", radius>0?"(Radius)":"(NN)", dbName, (key&&strlen(key))?key:inFile);
 	ws_query_by_key(dbName, key, inFile, (char*)hostport);	
@@ -71,18 +48,13 @@
 	VERB_LOG(1, "Calling web services query on database %s, query=%s\n", dbName, (key&&strlen(key))?key:inFile);
 	ws_query(dbName, inFile, (char*)hostport);
       }
-#endif
     }
     else
       query(dbName, inFile);
 
   else if(O2_ACTION(COM_STATUS))
     if(isClient)
-#ifdef LIBRARY
-      ;
-#else
       ws_status(dbName,(char*)hostport);
-#endif
     else
       status(dbName);
 
@@ -100,11 +72,7 @@
 
   else if(O2_ACTION(COM_LISZT))
     if(isClient)
-#ifdef LIBRARY
-      ;
-#else 
       ws_liszt(dbName, (char*) hostport);
-#endif
     else
       liszt(dbName, lisztOffset, lisztLength);
 
@@ -163,153 +131,12 @@
   }
 }
 
-
-//for the lib / API
-audioDB::audioDB(const unsigned argc, const char *argv[], int * apierror): O2_AUDIODB_INITIALIZERS
-{
-
-    try {
-        UseApiError=1;
-
-        if(processArgs(argc, argv)<0){
-            printf("No command found.\n");
-            cmdline_parser_print_version ();
-            if (strlen(gengetopt_args_info_purpose) > 0)
-                printf("%s\n", gengetopt_args_info_purpose);
-            printf("%s\n", gengetopt_args_info_usage);
-            printf("%s\n", gengetopt_args_info_help[1]);
-            printf("%s\n", gengetopt_args_info_help[2]);
-            printf("%s\n", gengetopt_args_info_help[0]);
-            error("No command found");
-        }
-
-        adb__queryResponse adbq;
-
-        if(O2_ACTION(COM_CREATE))
-            create(dbName);
-
-        else if(O2_ACTION(COM_INSERT))
-            insert(dbName, inFile);
-
-        else if(O2_ACTION(COM_BATCHINSERT))
-            batchinsert(dbName, inFile);
-
-        else if(O2_ACTION(COM_QUERY))
-            if(isClient)
-                ;//ws_query(dbName, inFile, (char*)hostport);
-            else
-                query(dbName, inFile, &adbq);
-        //query(dbName, inFile);
-
-        else if(O2_ACTION(COM_STATUS))
-            if(isClient)
-                ;//ws_status(dbName,(char*)hostport);
-            else
-                status(dbName);
-
-        else if(O2_ACTION(COM_L2NORM))
-            l2norm(dbName);
-
-        else if(O2_ACTION(COM_POWER))
-            power_flag(dbName);
-
-        else if(O2_ACTION(COM_DUMP))
-            dump(dbName);
-
-        else
-            error("Unrecognized command",command);
-
-    } catch(int a) {
-        *apierror=a;
-        return;
-
-    }
-    *apierror=apierrortemp;
-    return;
-
-}
-
-//for API status
-audioDB::audioDB(const unsigned argc, const char *argv[], cppstatusptr stat, int * apierror): O2_AUDIODB_INITIALIZERS
-{
-
-    try {
-        UseApiError=1;
-
-
-        if(processArgs(argc, argv)<0){
-            printf("No command found.\n");
-            cmdline_parser_print_version ();
-            if (strlen(gengetopt_args_info_purpose) > 0)
-                printf("%s\n", gengetopt_args_info_purpose);
-            printf("%s\n", gengetopt_args_info_usage);
-            printf("%s\n", gengetopt_args_info_help[1]);
-            printf("%s\n", gengetopt_args_info_help[2]);
-            printf("%s\n", gengetopt_args_info_help[0]);
-            error("No command found");
-        }
-
-        status(dbName, stat);
-
-
-    } catch(int a) {
-        *apierror=a;
-        return;
-
-    }
-    *apierror=apierrortemp;
-    return;
-
-}
-
-
-//for API query
-audioDB::audioDB(const unsigned argc, const char *argv[],adb__queryResponse *adbQueryResponse, int * apierror): O2_AUDIODB_INITIALIZERS
-{
-
-    try {
-        UseApiError=1;
-
-        if(processArgs(argc, argv)<0){
-            printf("No command found.\n");
-            cmdline_parser_print_version ();
-            if (strlen(gengetopt_args_info_purpose) > 0)
-                printf("%s\n", gengetopt_args_info_purpose);
-            printf("%s\n", gengetopt_args_info_usage);
-            printf("%s\n", gengetopt_args_info_help[1]);
-            printf("%s\n", gengetopt_args_info_help[2]);
-            printf("%s\n", gengetopt_args_info_help[0]);
-            error("No command found");
-        }
-
-        query(dbName, inFile, adbQueryResponse);
-
-    } catch(int a) {
-        *apierror=a;
-        return;
-
-    }
-    *apierror=apierrortemp;
-    return;
-
-}
-
-
-
-
-
 void audioDB::cleanup() {
   cmdline_parser_free(&args_info);
-  if(indata)
-    munmap(indata,statbuf.st_size);
-  if(db)
-    munmap(db,getpagesize());
   if(fileTable)
     munmap(fileTable, fileTableLength);
   if(trackTable)
     munmap(trackTable, trackTableLength);
-  if(dataBuf)
-    munmap(dataBuf, dataBufLength);
   if(timesTable)
     munmap(timesTable, timesTableLength);
   if(powerTable)
@@ -322,25 +149,19 @@
     munmap(timesFileNameTable, fileTableLength);
   if(powerFileNameTable)
     munmap(powerFileNameTable, fileTableLength);
-  if(trackOffsetTable)
-    delete [] trackOffsetTable;
   if(reporter)
     delete reporter;
-  if(exact_evaluation_queue)
-    delete exact_evaluation_queue;
   if(allowed_keys)
     delete allowed_keys;
   if(rng)
     gsl_rng_free(rng);
-  if(vv)
-    delete vv;
-  if(dbfid>0)
-    close(dbfid);
   if(infid>0)
     close(infid);
-  if(dbH)
-    delete dbH;
-  if(lsh!=SERVER_LSH_INDEX_SINGLETON)
+  if(adb) {
+    audiodb_close(adb);
+    adb = NULL;
+  }
+  if(lsh)
     delete lsh;
 }
 
@@ -743,613 +564,388 @@
 }
 
 void audioDB::status(const char* dbName, adb__statusResponse *adbStatusResponse){
-  if(!dbH)
-    initTables(dbName, 0);
-
-  unsigned dudCount=0;
-  unsigned nullCount=0;
-  for(unsigned k=0; k<dbH->numFiles; k++){
-    if(trackTable[k]<sequenceLength){
-      dudCount++;
-      if(!trackTable[k])
-        nullCount++;
+  adb_status_t status;
+  if(!adb) {
+    if(!(adb = audiodb_open(dbName, O_RDONLY))) {
+      error("Failed to open database file", dbName);
     }
   }
+  if(audiodb_status(adb, &status)) {
+    error("Failed to retrieve database status", dbName);
+  }
   
   if(adbStatusResponse == 0) {
-
-    // Update Header information
-    std::cout << "num files:" << dbH->numFiles << std::endl;
-    std::cout << "data dim:" << dbH->dim <<std::endl;
-    if(dbH->dim>0){
-      std::cout << "total vectors:" << dbH->length/(sizeof(double)*dbH->dim)<<std::endl;
-      if(dbH->flags & O2_FLAG_LARGE_ADB)
-	std::cout << "vectors available:" << O2_MAX_VECTORS - (dbH->length / (sizeof(double)*dbH->dim)) << std::endl;
-      else
-	std::cout << "vectors available:" << (dbH->timesTableOffset-(dbH->dataOffset+dbH->length))/(sizeof(double)*dbH->dim) << std::endl;
+    std::cout << "num files:" << status.numFiles << std::endl;
+    std::cout << "data dim:" << status.dim <<std::endl;
+    if(status.dim > 0) {
+      size_t bytes_per_vector = sizeof(double) * status.dim;
+      off_t nvectors = status.length / bytes_per_vector;
+      off_t data_region_vectors = status.data_region_size / bytes_per_vector;
+      std::cout << "total vectors:" << nvectors << std::endl;
+      std::cout << "vectors available:";
+      if(status.flags & O2_FLAG_LARGE_ADB) {
+	std::cout << O2_MAX_VECTORS - nvectors << std::endl;
+      } else {
+	std::cout << data_region_vectors - nvectors << std::endl;
+      }
     }
-    if( ! (dbH->flags & O2_FLAG_LARGE_ADB) ){
-      std::cout << "total bytes:" << dbH->length << " (" << (100.0*dbH->length)/(dbH->timesTableOffset-dbH->dataOffset) << "%)" << std::endl;
-      std::cout << "bytes available:" << dbH->timesTableOffset-(dbH->dataOffset+dbH->length) << " (" <<
-	(100.0*(dbH->timesTableOffset-(dbH->dataOffset+dbH->length)))/(dbH->timesTableOffset-dbH->dataOffset) << "%)" << std::endl;
+    if(!(status.flags & O2_FLAG_LARGE_ADB)) {
+      double used_frac = ((double) status.length) / status.data_region_size;
+      std::cout << "total bytes:" << status.length << 
+	" (" << (100.0*used_frac) << "%)" << std::endl;
+      std::cout << "bytes available:" << status.data_region_size - status.length << 
+	" (" << (100.0*(1-used_frac)) << "%)" << std::endl;
     }
-    std::cout << "flags:" << " l2norm[" << DISPLAY_FLAG(dbH->flags&O2_FLAG_L2NORM)
-	      << "] minmax[" << DISPLAY_FLAG(dbH->flags&O2_FLAG_MINMAX)
-	      << "] power[" << DISPLAY_FLAG(dbH->flags&O2_FLAG_POWER)
-	      << "] times[" << DISPLAY_FLAG(dbH->flags&O2_FLAG_TIMES) 
-	      << "] largeADB[" << DISPLAY_FLAG(dbH->flags&O2_FLAG_LARGE_ADB)
+    std::cout << "flags:" << " l2norm[" << DISPLAY_FLAG(status.flags&O2_FLAG_L2NORM)
+	      << "] minmax[" << DISPLAY_FLAG(status.flags&O2_FLAG_MINMAX)
+	      << "] power[" << DISPLAY_FLAG(status.flags&O2_FLAG_POWER)
+	      << "] times[" << DISPLAY_FLAG(status.flags&O2_FLAG_TIMES) 
+	      << "] largeADB[" << DISPLAY_FLAG(status.flags&O2_FLAG_LARGE_ADB)
 	      << "]" << endl;    
               
-    std::cout << "null count: " << nullCount << " small sequence count " << dudCount-nullCount << std::endl;    
+    std::cout << "null count: " << status.nullCount << " small sequence count " << status.dudCount-status.nullCount << std::endl;    
   } else {
-    adbStatusResponse->result.numFiles = dbH->numFiles;
-    adbStatusResponse->result.dim = dbH->dim;
-    adbStatusResponse->result.length = dbH->length;
-    adbStatusResponse->result.dudCount = dudCount;
-    adbStatusResponse->result.nullCount = nullCount;
-    adbStatusResponse->result.flags = dbH->flags;
+    adbStatusResponse->result.numFiles = status.numFiles;
+    adbStatusResponse->result.dim = status.dim;
+    adbStatusResponse->result.length = status.length;
+    adbStatusResponse->result.dudCount = status.dudCount;
+    adbStatusResponse->result.nullCount = status.nullCount;
+    adbStatusResponse->result.flags = status.flags;
   }
 }
 
-///used by lib/API
-void audioDB::status(const char* dbName, cppstatusptr status){
-    if(!dbH) {
-        initTables(dbName, 0);
-    }
-
-  unsigned dudCount=0;
-  unsigned nullCount=0;
-  for(unsigned k=0; k<dbH->numFiles; k++){
-    if(trackTable[k]<sequenceLength){
-      dudCount++;
-      if(!trackTable[k])
-        nullCount++;
+void audioDB::l2norm(const char* dbName) {
+  if(!adb) {
+    if(!(adb = audiodb_open(dbName, O_RDWR))) {
+      error("Failed to open database file", dbName);
     }
   }
-  
-  status->numFiles = dbH->numFiles;
-  status->dim = dbH->dim;
-  status->length = dbH->length;
-  status->dudCount = dudCount;
-  status->nullCount = nullCount;
-  status->flags = dbH->flags;
-  
-  return;
-}
-
-
-
-
-void audioDB::l2norm(const char* dbName) {
-  forWrite = true;
-  initTables(dbName, 0);
-  if( !(dbH->flags & O2_FLAG_LARGE_ADB ) && (dbH->length>0) ){
-    /* FIXME: should probably be uint64_t */
-    unsigned numVectors = dbH->length/(sizeof(double)*dbH->dim);
-    CHECKED_MMAP(double *, dataBuf, dbH->dataOffset, dataBufLength);
-    unitNormAndInsertL2(dataBuf, dbH->dim, numVectors, 0); // No append
+  if(audiodb_l2norm(adb)) {
+    error("failed to turn on l2norm flag for database", dbName);
   }
-  // Update database flags
-  dbH->flags = dbH->flags|O2_FLAG_L2NORM;
-  memcpy (db, dbH, O2_HEADERSIZE);
 }
 
 void audioDB::power_flag(const char *dbName) {
-  forWrite = true;
-  initTables(dbName, 0);  
-  if( !(dbH->flags & O2_FLAG_LARGE_ADB ) && (dbH->length>0) ){
-    error("cannot turn on power storage for non-empty database", dbName);
+  if(!adb) {
+    if(!(adb = audiodb_open(dbName, O_RDWR))) {
+      error("Failed to open database file", dbName);
+    }
   }
-  dbH->flags |= O2_FLAG_POWER;
-  memcpy(db, dbH, O2_HEADERSIZE);
+  if(audiodb_power(adb)) {
+    error("can't turn on power flag for database", dbName);
+  }
 }
 
-// Unit norm block of features
+void audioDB::create(const char *dbName) {
+  if(adb) {
+    error("Already have an adb in this object", "");
+  }
+  if(!(adb = audiodb_create(dbName, datasize, ntracks, datadim))) {
+    error("Failed to create database file", dbName);
+  }
+}
 
-/* FIXME: in fact this does not unit norm a block of features, it just
-   records the L2 norms somewhere.  unitNorm() does in fact unit norm
-   a block of features. */
-void audioDB::unitNormAndInsertL2(double* X, unsigned dim, unsigned n, unsigned append=0){
-  unsigned d;
-  double *p;
-  unsigned nn = n;
+void audioDB::dump(const char *dbName) {
+  if(!adb) {
+    if(!(adb = audiodb_open(dbName, O_RDONLY))) {
+      error("Failed to open database file", dbName);
+    }
+  }
+  if(audiodb_dump(adb, output)) {
+    error("Failed to dump database to ", output);
+  }
+  status(dbName);
+}
 
-  assert(l2normTable);
+void audioDB::insert(const char* dbName, const char* inFile) {
+  if(!adb) {
+    if(!(adb = audiodb_open(dbName, O_RDWR))) {
+      error("failed to open database", dbName);
+    }
+  }
 
-  if( !(dbH->flags & O2_FLAG_LARGE_ADB) && !append && (dbH->flags & O2_FLAG_L2NORM) )
-    error("Database is already L2 normed", "automatic norm on insert is enabled");
+  /* at this point, we have powerfd (an fd), timesFile (a
+   * std::ifstream *) and inFile (a char *).  Wacky, huh?  Ignore
+   * the wackiness and just use the names. */
+  adb_insert_t insert;
+  insert.features = inFile;
+  insert.times = timesFileName;
+  insert.power = powerFileName;
+  insert.key = key;
 
-  VERB_LOG(2, "norming %u vectors...", n);
+  if(audiodb_insert(adb, &insert)) {
+    error("insertion failure", inFile);
+  }
+  status(dbName);
+}
 
-  double* l2buf = new double[n];
-  double* l2ptr = l2buf;
-  assert(l2buf);
-  assert(X);
+void audioDB::batchinsert(const char* dbName, const char* inFile) {
+  if(!adb) {
+    if(!(adb = audiodb_open(dbName, O_RDWR))) {
+      error("failed to open database", dbName);
+    }
+  }
 
-  while(nn--){
-    p=X;
-    *l2ptr=0.0;
-    d=dim;
-    while(d--){
-      *l2ptr+=*p**p;
-      p++;
+  if(!key)
+    key=inFile;
+  std::ifstream *filesIn = 0;
+  std::ifstream *keysIn = 0;
+
+  if(!(filesIn = new std::ifstream(inFile)))
+    error("Could not open batch in file", inFile);
+  if(key && key!=inFile)
+    if(!(keysIn = new std::ifstream(key)))
+      error("Could not open batch key file",key);
+
+  unsigned totalVectors=0;
+  char *thisFile = new char[MAXSTR];
+  char *thisKey = 0;
+  if (key && (key != inFile)) {
+    thisKey = new char[MAXSTR];
+  }
+  char *thisTimesFileName = new char[MAXSTR];
+  char *thisPowerFileName = new char[MAXSTR];
+
+  do {
+    filesIn->getline(thisFile,MAXSTR);
+    if(key && key!=inFile) {
+      keysIn->getline(thisKey,MAXSTR);
+    } else {
+      thisKey = thisFile;
     }
-    l2ptr++;
-    X+=dim;
+    if(usingTimes) {
+      timesFile->getline(thisTimesFileName,MAXSTR);
+    }
+    if(usingPower) {
+      powerFile->getline(thisPowerFileName, MAXSTR);
+    }
+    
+    if(filesIn->eof()) {
+      break;
+    }
+    if(usingTimes){
+      if(timesFile->eof()) {
+        error("not enough timestamp files in timesList", timesFileName);
+      }
+    }
+    if (usingPower) {
+      if(powerFile->eof()) {
+        error("not enough power files in powerList", powerFileName);
+      }
+    }
+    adb_insert_t insert;
+    insert.features = thisFile;
+    insert.times = usingTimes ? thisTimesFileName : NULL;
+    insert.power = usingPower ? thisPowerFileName : NULL;
+    insert.key = thisKey;
+    if(audiodb_insert(adb, &insert)) {
+      error("insertion failure", thisFile);
+    }
+  } while(!filesIn->eof());
+
+  VERB_LOG(0, "%s %s %u vectors %ju bytes.\n", COM_BATCHINSERT, dbName, totalVectors, (intmax_t) (totalVectors * dbH->dim * sizeof(double)));
+
+  delete [] thisPowerFileName;
+  if(key && (key != inFile)) {
+    delete [] thisKey;
   }
-  unsigned offset;
-  if(append) {
-    // FIXME: a hack, a very palpable hack: the vectors have already
-    // been inserted, and dbH->length has already been updated.  We
-    // need to subtract off again the number of vectors that we've
-    // inserted this time...
-    offset=(dbH->length/(dbH->dim*sizeof(double)))-n; // number of vectors
+  delete [] thisFile;
+  delete [] thisTimesFileName;
+  
+  delete filesIn;
+  delete keysIn;
+
+  // Report status
+  status(dbName);
+}
+
+void audioDB::query(const char* dbName, const char* inFile, adb__queryResponse *adbQueryResponse) {
+
+  if(!adb) {
+    if(!(adb = audiodb_open(dbName, O_RDWR))) {
+      error("failed to open database", dbName);
+    }
+  }
+
+  /* FIXME: we only need this for getting nfiles, which we only need
+   * because the reporters aren't desperately well implemented,
+   * relying on statically-sized vectors rather than adjustable data
+   * structures.  Rework reporter.h to be less lame. */
+  adb_status_t status;
+  audiodb_status(adb, &status);
+  uint32_t nfiles = status.numFiles;
+
+  adb_query_spec_t qspec;
+  adb_datum_t datum = {0};
+
+  qspec.refine.flags = 0;
+  if(trackFile) {
+    qspec.refine.flags |= ADB_REFINE_INCLUDE_KEYLIST;
+    std::vector<const char *> v;
+    char *k = new char[MAXSTR];
+    trackFile->getline(k, MAXSTR);    
+    while(!trackFile->eof()) {
+      v.push_back(k);
+      k = new char[MAXSTR];
+      trackFile->getline(k, MAXSTR);    
+    }
+    delete [] k;
+    qspec.refine.include.nkeys = v.size();
+    qspec.refine.include.keys = new const char *[qspec.refine.include.nkeys];
+    for(unsigned int k = 0; k < qspec.refine.include.nkeys; k++) {
+      qspec.refine.include.keys[k] = v[k];
+    }
+  }
+  if(query_from_key) {
+    qspec.refine.flags |= ADB_REFINE_EXCLUDE_KEYLIST;
+    qspec.refine.exclude.nkeys = 1;
+    qspec.refine.exclude.keys = &key;
+  }
+  if(radius) {
+    qspec.refine.flags |= ADB_REFINE_RADIUS;
+    qspec.refine.radius = radius;
+  }
+  if(use_absolute_threshold) {
+    qspec.refine.flags |= ADB_REFINE_ABSOLUTE_THRESHOLD;
+    qspec.refine.absolute_threshold = absolute_threshold;
+  }
+  if(use_relative_threshold) {
+    qspec.refine.flags |= ADB_REFINE_RELATIVE_THRESHOLD;
+    qspec.refine.relative_threshold = relative_threshold;
+  }
+  if(usingTimes) {
+    qspec.refine.flags |= ADB_REFINE_DURATION_RATIO;
+    qspec.refine.duration_ratio = timesTol;
+  }
+  /* FIXME: not sure about this any more; maybe it belongs in
+     query_id?  Or maybe we just don't need a flag for it? */
+  qspec.refine.hopsize = sequenceHop;
+  if(sequenceHop != 1) {
+    qspec.refine.flags |= ADB_REFINE_HOP_SIZE;
+  }
+
+  if(query_from_key) {
+    datum.key = key;
   } else {
-    offset=0;
+    int fd;
+    struct stat st;
+
+    /* FIXME: around here there are all sorts of hideous leaks. */
+    fd = open(inFile, O_RDONLY);
+    if(fd < 0) {
+      error("failed to open feature file", inFile);
+    }
+    fstat(fd, &st);
+    read(fd, &datum.dim, sizeof(uint32_t));
+    datum.nvectors = (st.st_size - sizeof(uint32_t)) / (datum.dim * sizeof(double));
+    datum.data = (double *) malloc(st.st_size - sizeof(uint32_t));
+    read(fd, datum.data, st.st_size - sizeof(uint32_t));
+    close(fd);
+    if(usingPower) {
+      uint32_t one;
+      fd = open(powerFileName, O_RDONLY);
+      if(fd < 0) {
+        error("failed to open power file", powerFileName);
+      }
+      read(fd, &one, sizeof(uint32_t));
+      if(one != 1) {
+        error("malformed power file dimensionality", powerFileName);
+      }
+      datum.power = (double *) malloc(datum.nvectors * sizeof(double));
+      if(read(fd, datum.power, datum.nvectors * sizeof(double)) != (ssize_t) (datum.nvectors * sizeof(double))) {
+        error("malformed power file", powerFileName);
+      }
+      close(fd);
+    }
+    if(usingTimes) {
+      datum.times = (double *) malloc(2 * datum.nvectors * sizeof(double));
+      insertTimeStamps(datum.nvectors, timesFile, datum.times);
+    }
   }
-  memcpy(l2normTable+offset, l2buf, n*sizeof(double));
-  if(l2buf)
-    delete[] l2buf;
-  VERB_LOG(2, " done.");
+
+  qspec.qid.datum = &datum;
+  qspec.qid.sequence_length = sequenceLength;
+  qspec.qid.flags = 0;
+  qspec.qid.flags |= usingQueryPoint ? 0 : ADB_QID_FLAG_EXHAUSTIVE;
+  qspec.qid.flags |= lsh_exact ? 0 : ADB_QID_FLAG_ALLOW_FALSE_POSITIVES;
+  qspec.qid.sequence_start = queryPoint;
+
+  switch(queryType) {
+  case O2_POINT_QUERY:
+    qspec.qid.sequence_length = 1;
+    qspec.params.accumulation = ADB_ACCUMULATION_DB;
+    qspec.params.distance = ADB_DISTANCE_DOT_PRODUCT;
+    qspec.params.npoints = pointNN;
+    qspec.params.ntracks = 0;
+    reporter = new pointQueryReporter< std::greater < NNresult > >(pointNN);
+    break;
+  case O2_TRACK_QUERY:
+    qspec.qid.sequence_length = 1;
+    qspec.params.accumulation = ADB_ACCUMULATION_PER_TRACK;
+    qspec.params.distance = ADB_DISTANCE_DOT_PRODUCT;
+    qspec.params.npoints = pointNN;
+    qspec.params.ntracks = trackNN;
+    reporter = new trackAveragingReporter< std::greater< NNresult > >(pointNN, trackNN, nfiles);
+    break;
+  case O2_SEQUENCE_QUERY:
+  case O2_N_SEQUENCE_QUERY:
+    qspec.params.accumulation = ADB_ACCUMULATION_PER_TRACK;
+    qspec.params.distance = no_unit_norming ? ADB_DISTANCE_EUCLIDEAN : ADB_DISTANCE_EUCLIDEAN_NORMED;
+    qspec.params.npoints = pointNN;
+    qspec.params.ntracks = trackNN;
+    switch(queryType) {
+    case O2_SEQUENCE_QUERY:
+      if(!(qspec.refine.flags & ADB_REFINE_RADIUS)) {
+        reporter = new trackAveragingReporter< std::less< NNresult > >(pointNN, trackNN, nfiles);
+      } else {
+	reporter = new trackSequenceQueryRadReporter(trackNN, nfiles);
+      }
+      break;
+    case O2_N_SEQUENCE_QUERY:
+      if(!(qspec.refine.flags & ADB_REFINE_RADIUS)) {
+        reporter = new trackSequenceQueryNNReporter< std::less < NNresult > >(pointNN, trackNN, nfiles);
+      } else {
+	reporter = new trackSequenceQueryRadNNReporter(pointNN, trackNN, nfiles);
+      }
+      break;
+    }
+    break;
+  case O2_ONE_TO_ONE_N_SEQUENCE_QUERY:
+    qspec.params.accumulation = ADB_ACCUMULATION_ONE_TO_ONE;
+    qspec.params.distance = no_unit_norming ? ADB_DISTANCE_EUCLIDEAN : ADB_DISTANCE_EUCLIDEAN_NORMED;
+    qspec.params.npoints = 0;
+    qspec.params.ntracks = 0;
+    if(!(qspec.refine.flags & ADB_REFINE_RADIUS)) {
+      error("query-type not yet supported");
+    } else {
+      reporter = new trackSequenceQueryRadNNReporterOneToOne(pointNN,trackNN, dbH->numFiles);
+    }
+    break;
+  default:
+    error("unrecognized queryType");
+  }
+
+  adb_query_results_t *rs = audiodb_query_spec(adb, &qspec);
+
+  // FIXME: free bits of datum if !query_from_key
+
+  if(rs == NULL) {
+    error("audiodb_query_spec failed");
+  }
+
+  for(unsigned int k = 0; k < rs->nresults; k++) {
+    adb_result_t r = rs->results[k];
+    reporter->add_point(audiodb_key_index(adb, r.key), r.qpos, r.ipos, r.dist);
+  }
+  audiodb_query_free_results(adb, &qspec, rs);
+
+  reporter->report(adb, adbQueryResponse);
 }
 
 // This entry point is visited once per instance
 // so it is a good place to set any global state variables
 int main(const int argc, const char* argv[]){
-  SERVER_LSH_INDEX_SINGLETON = 0; // Initialize global variables
   SERVER_ADB_ROOT = 0;            // Server-side database root prefix
   SERVER_ADB_FEATURE_ROOT = 0;    // Server-side features root prefix
   audioDB(argc, argv);
 }
-
-
-extern "C" {
-
-/* for API questions contact 
- * Christophe Rhodes c.rhodes@gold.ac.uk
- * Ian Knopke mas01ik@gold.ac.uk, ian.knopke@gmail.com */
-
-#include "audioDB_API.h"
-
-    adb_ptr audiodb_create(const char *path, unsigned datasize, unsigned ntracks, unsigned datadim) {
-        const char *argv[12];
-        int argvctr=0;
-        char tempstr1[200];
-        char tempstr2[200];
-        char tempstr3[200];
-        int apierror=0;
-
-
-        argv[argvctr++] = "audioDB";
-        argv[argvctr++] = "--NEW";
-        argv[argvctr++] = "-d";
-        argv[argvctr++] = path;
-
-        if (datasize >0){
-            argv[argvctr++]="--datasize";
-            snprintf(tempstr1,sizeof(tempstr1),"%u",datasize);
-            argv[argvctr++]=tempstr1;
-        }
-
-        if (ntracks >0){
-            argv[argvctr++]="--ntracks";
-            snprintf(tempstr2,sizeof(tempstr2),"%u",ntracks);
-            argv[argvctr++]=tempstr2;
-        }
-
-        if (datadim > 0){
-            argv[argvctr++]="--datadim";
-            snprintf(tempstr3,sizeof(tempstr3),"%u",datadim);
-            argv[argvctr++]=tempstr3;
-        }
-
-        argv[argvctr]='\0';
-
-        audioDB::audioDB(argvctr, argv, &apierror);
-
-        if (!apierror){ 
-            return audiodb_open(path);
-        }
-
-        /* database exists, so fail and pass NULL */
-        return NULL;
-    }
-
-
-
-  int audiodb_insert(adb_ptr mydb, adb_insert_ptr ins) {
-    const char *argv[15];
-    int argvctr=0;
-    int apierror=0;
-
-    argv[argvctr++]="audioDB";
-    argv[argvctr++]="-I";
-    argv[argvctr++]="-d";
-    argv[argvctr++]=mydb->dbname;
-    argv[argvctr++]="-f";
-    argv[argvctr++]=ins->features;
-
-    if (ins->times){
-        argv[argvctr++]="--times";
-        argv[argvctr++]=ins->times;
-    }
-
-    if (ins->power){
-        argv[argvctr++]="-w";
-        argv[argvctr++]=ins->power;
-    }
-
-    if (ins->key){
-        argv[argvctr++]="--key";
-        argv[argvctr++]=ins->key;
-    }
-    argv[argvctr]='\0';
-
-    audioDB::audioDB(argvctr,argv,&apierror);
-    return apierror;
-  }
-
-
-  int audiodb_batchinsert(adb_ptr mydb, adb_insert_ptr ins, unsigned int size) {
-
-    const char *argv[22];
-    int argvctr=0;
-    unsigned int i=0;
-    char tempfeaturename[]="tempfeatureXXXXXX";
-    char temppowername[]="temppowerXXXXXX";
-    char tempkeyname[]="tempkeyXXXXXX";
-    char temptimesname[]="temptimesXXXXXX";
-    int tempfeaturefd = -1;
-    int temppowerfd = -1;
-    int tempkeyfd = -1;
-    int temptimesfd = -1;
-
-    int flags[4]={0};
-    int apierror=0;
-
-    /*  So the final API should take an array of structs. However, the current 
-    *   version requires four separate text files. So temporarily, we need to
-    *   unpack the struct array, make four separate text files, and then reinsert
-    *   them into the command-line call. This should change as soon as possible */
-
-
-    argv[argvctr++]="audioDB";
-    argv[argvctr++]="-B";
-    argv[argvctr++]="-d";
-    argv[argvctr++]=mydb->dbname;
-
-
-    /* assume struct is well formed for all entries */
-    if (ins[0].features){ flags[0]++;} else {
-        /* short circuit the case where there are no features in the structs */
-        return -1;
-    } ;
-    if (ins[0].power){ flags[1]++;};
-    if (ins[0].key){ flags[2]++;};
-    if (ins[0].times){ flags[3]++;};
-
-
-    /* make four temp files */
-    if ((tempfeaturefd = mkstemp(tempfeaturename)) == -1)
-      goto error;
-    if ((temppowerfd = mkstemp(temppowername)) == -1)
-      goto error;
-    if ((tempkeyfd=mkstemp(tempkeyname)) == -1)
-      goto error;
-    if ((temptimesfd=mkstemp(temptimesname)) == -1)
-      goto error;
-
-    /* Ok, so we should have a working set of files to write to */ 
-    /* I'm going to assume that the same format is kept for all structs in the array */
-    /* That is, each struct should be correctly formed, and contain at least a features file, because I'm just going to pass the terms along to the text files */
-    for (i = 0; i < size; i++) {
-      if (write(tempfeaturefd,ins[i].features,strlen(ins[i].features)) != (ssize_t) strlen(ins[i].features))
-	goto error;
-      if (write(tempfeaturefd,"\n",1) != 1)
-	goto error;
-
-      if (flags[1]) {
-	if (write(temppowerfd,ins[i].power,strlen(ins[i].power)) != (ssize_t) strlen(ins[i].power))
-	  goto error;
-	if (write(temppowerfd,"\n",1) != 1)
-	  goto error;
-      }
-      if (flags[2]) {
-	if (write(tempkeyfd,ins[i].key,strlen(ins[i].key)) != (ssize_t) strlen(ins[i].key))
-	  goto error;
-	if (write(tempkeyfd,"\n",1) != 1)
-	  goto error;
-      }
-      if (flags[3]) {
-	if (write(temptimesfd,ins[i].times,strlen(ins[i].times)) != (ssize_t) strlen(ins[i].times))
-	  goto error;
-	if (write(temptimesfd,"\n",1) != 1)
-	  goto error;
-      }
-    }
-
-    argv[argvctr++]="-F";
-    argv[argvctr++]=tempfeaturename;
-    close(tempfeaturefd);
-    close(temppowerfd);
-    close(tempkeyfd);
-    close(temptimesfd);
-
-    if (flags[1]){
-        argv[argvctr++]="--powerList";
-        argv[argvctr++]=temppowername;
-    }
-
-    if (flags[2]){
-        argv[argvctr++]="--keyList";
-        argv[argvctr++]=tempkeyname;
-    }
-
-    if (flags[3]){
-        argv[argvctr++]="--timesList";
-        argv[argvctr++]=temptimesname;
-    }
-
-    argv[argvctr]='\0';
-
-    audioDB::audioDB(argvctr,argv,&apierror);
-
-    remove(tempfeaturename);
-    remove(temppowername);
-    remove(tempkeyname);
-    remove(temptimesname);
-
-
-    return apierror;
-
-  error:
-    if(tempfeaturefd != -1) {
-      close(tempfeaturefd);
-      remove(tempfeaturename);
-    }
-    if(temppowerfd != -1) {
-      close(temppowerfd);
-      remove(temppowername);
-    }
-    if(tempkeyfd != -1) {
-      close(tempkeyfd);
-      remove(tempkeyname);
-    }
-    if(temptimesfd != -1) {
-      close(temptimesfd);
-      remove(temptimesname);
-    }
-    return -1;
-  }
-
-
-  int audiodb_query(adb_ptr mydb, adb_query_ptr adbq, adb_queryresult_ptr adbqr){
-
-    const char *argv[32];
-    int argvctr=0;
-    char tempstr1[200];
-    char tempstr2[200];
-    char tempstr3[200];
-    int apierror=0;
-
-    adb__queryResponse adbQueryResponse; 
-
-    /* TODO: may need error checking here */
-    /* currently counting on audioDB binary to fail for me */
-    argv[argvctr++]="audioDB";
-    
-    if(adbq->querytype){
-        argv[argvctr++]="-Q";
-        argv[argvctr++]=adbq->querytype;
-    }
-
-    if(mydb->dbname){
-        argv[argvctr++]="-d";
-        argv[argvctr++]=mydb->dbname;
-    }
-
-    if (adbq->feature){
-        argv[argvctr++]="-f";
-        argv[argvctr++]=adbq->feature;
-    }
-
-    if (adbq->key){
-        argv[argvctr++]="-k";
-        argv[argvctr++]=adbq->key;
-    }
-
-    if (adbq->power){
-        argv[argvctr++]="-w";
-        argv[argvctr++]=adbq->power;
-    }
-
-    if (adbq->qpoint){
-        argv[argvctr++]="-p";
-        argv[argvctr++]=adbq->qpoint;
-    }
-    if (adbq->numpoints){
-        argv[argvctr++]="-n";
-        argv[argvctr++]=adbq->numpoints;
-    }
-    if (adbq->radius){
-        argv[argvctr++]="-R";
-        argv[argvctr++]=adbq->radius;
-    }
-    if(adbq->resultlength){
-        argv[argvctr++]="-r";
-        argv[argvctr++]=adbq->resultlength;
-    }
-    if(adbq->sequencelength){
-        argv[argvctr++]="-l";
-        argv[argvctr++]=adbq->sequencelength;
-    }
-    if(adbq->sequencehop){
-        argv[argvctr++]="-h";
-        argv[argvctr++]=adbq->sequencehop;
-    }
-
-    if (adbq->absolute_threshold){
-        argv[argvctr++]="--absolute-threshold";
-        snprintf(tempstr1,sizeof(tempstr1),"%f",adbq->absolute_threshold);
-        argv[argvctr++]=tempstr1;
-    }
-
-    if (adbq->relative_threshold){
-        argv[argvctr++]="--relative-threshold";
-        snprintf(tempstr2,sizeof(tempstr2),"%f",adbq->relative_threshold);
-        argv[argvctr++]=tempstr2;
-    }
-
-    if (adbq->exhaustive){
-        argv[argvctr++]="--exhaustive";
-    }
-
-    if (adbq->expandfactor){
-        argv[argvctr++]="--expandfactor";
-        snprintf(tempstr3,sizeof(tempstr3),"%f",adbq->expandfactor);
-        argv[argvctr++]=tempstr3;
-    }
-
-    if (adbq->rotate){
-        argv[argvctr++]="--rotate";
-    }
-
-    if (adbq->keylist){
-        argv[argvctr++]="-K";
-        argv[argvctr++]=adbq->keylist;
-    }
-    argv[argvctr]='\0';
-
-    /* debugging */
-
-    audioDB::audioDB(argvctr,argv, &adbQueryResponse, &apierror);
-
-    //copy data over here from adbQueryResponse to adbqr
-    adbqr->sizeRlist=adbQueryResponse.result.__sizeRlist;
-    adbqr->sizeDist=adbQueryResponse.result.__sizeDist;
-    adbqr->sizeQpos=adbQueryResponse.result.__sizeQpos;
-    adbqr->sizeSpos=adbQueryResponse.result.__sizeSpos;
-    adbqr->Rlist=adbQueryResponse.result.Rlist;
-    adbqr->Dist=adbQueryResponse.result.Dist;
-    adbqr->Qpos=adbQueryResponse.result.Qpos;
-    adbqr->Spos=adbQueryResponse.result.Spos;
-
-    return apierror;
-  }
-
-  ///* status command */
-  int audiodb_status(adb_ptr mydb, adb_status_ptr status){
-
-      cppstatus sss;
-      int apierror=0;
-
-      const char *argv[5];
-
-      apierror=0;
-      argv[0]="audioDB";
-      argv[1]="--STATUS";
-      argv[2]="-d";
-      argv[3]=mydb->dbname;
-      argv[4]='\0';
-
-      audioDB::audioDB(4,argv,&sss ,&apierror);
-      
-      status->numFiles=sss.numFiles;
-      status->dim=sss.dim;
-      status->length=sss.length;
-      status->dudCount=sss.dudCount;
-      status->nullCount=sss.nullCount;
-      status->flags=sss.flags;
-
-      return apierror;
-  }
-
-  int audiodb_dump(adb_ptr mydb){
-      return audiodb_dump_withdir(mydb,"audioDB.dump");
-  }
-
-  int audiodb_dump_withdir(adb_ptr mydb, const char *outputdir){
-
-      const char *argv[7];
-      int argvctr=0;
-      int apierror=0;
-
-      argv[argvctr++]="audioDB";
-      argv[argvctr++]="--DUMP";
-      argv[argvctr++]="-d";
-      argv[argvctr++]=mydb->dbname;
-      argv[argvctr++]="--output";
-      argv[argvctr++]=(char *)outputdir;
-      argv[argvctr]='\0';
-
-      audioDB::audioDB(6,argv,&apierror);
-
-      return apierror;
-  }
-
-  int audiodb_l2norm(adb_ptr mydb){
-
-      const char *argv[5];
-      int apierror=0;
-
-      argv[0]="audioDB";
-      argv[1]="--L2NORM";
-      argv[2]="-d";
-      argv[3]=mydb->dbname;
-      argv[4]='\0';
-
-      audioDB::audioDB(4,argv,&apierror);
-      return apierror;
-  }
-
-  int audiodb_power(adb_ptr mydb){
-
-      const char *argv[5];
-      int apierror=0;
-
-      argv[0]="audioDB";
-      argv[1]="--POWER";
-      argv[2]="-d";
-      argv[3]=mydb->dbname;
-      argv[4]='\0';
-
-      audioDB::audioDB(4,argv,&apierror);
-      return apierror;
-  }
-
-  adb_ptr audiodb_open(const char *path){
-
-        adb_ptr mydbp;
-        adbstatus mystatus;
-
-        /* if db exists */
-
-        if (open(path, O_EXCL) != -1){
-
-            mydbp=(adb_ptr)malloc(sizeof(adb));
-            mydbp->dbname=(char *)malloc(1+strlen(path));
-
-            strcpy(mydbp->dbname,path); 
-
-            audiodb_status(mydbp, &mystatus);
-            mydbp->ntracks=mystatus.numFiles;
-            mydbp->datadim=mystatus.dim;
-
-            return mydbp;
-        }
-
-        return NULL;
-  };
-
-
-
-  void audiodb_close(adb_ptr db){
-
-      free(db->dbname);
-      free(db);
-
-  }
-
-
-}
-