changeset 469:d3afc91d205d api-inversion

Move audioDB::query over to audioDB.cpp At the same time, remove all the abstraction violations in audioDB::query, which came in two flavours: use of dbH->numFiles, which is dealt with by getting the database status instead (and is eventually unnecessary, being only needed now because reporters are implemented in terms of vectors indexed by ID), and use of fileTable in reporter's report functions (dealt with by passing in the adb instead). To actually implement reporting as of now, we continue to use stuff from audioDB-internals.h; maybe someday we will be clean and shiny.
author mas01cr
date Wed, 31 Dec 2008 15:44:16 +0000
parents 4dbd7917bf9e
children c26c5b7ef0d2
files ReporterBase.h audioDB-internals.h audioDB.cpp audioDB_API.h common.cpp query.cpp reporter.h
diffstat 7 files changed, 292 insertions(+), 270 deletions(-) [+]
line wrap: on
line diff
--- a/ReporterBase.h	Wed Dec 31 15:44:12 2008 +0000
+++ b/ReporterBase.h	Wed Dec 31 15:44:16 2008 +0000
@@ -6,7 +6,7 @@
 public:
   virtual ~ReporterBase(){};
   virtual void add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist) = 0;
-  virtual void report(char*,void*) = 0;
+  virtual void report(adb_t *,void *) = 0;
 };
 
 #endif
--- a/audioDB-internals.h	Wed Dec 31 15:44:12 2008 +0000
+++ b/audioDB-internals.h	Wed Dec 31 15:44:16 2008 +0000
@@ -226,6 +226,10 @@
   }
 }
 
+static inline const char *audiodb_index_key(adb_t *adb, uint32_t index) {
+  return (*adb->keys)[index].c_str();
+}
+
 static inline uint32_t audiodb_index_to_track_id(uint32_t lshid, uint32_t n_point_bits) {
   return (lshid >> n_point_bits);
 }
--- a/audioDB.cpp	Wed Dec 31 15:44:12 2008 +0000
+++ b/audioDB.cpp	Wed Dec 31 15:44:16 2008 +0000
@@ -3,6 +3,7 @@
 #include "audioDB_API.h"
 #include "audioDB-internals.h"
 }
+#include "reporter.h"
 
 char* SERVER_ADB_ROOT;
 char* SERVER_ADB_FEATURE_ROOT;
@@ -822,6 +823,184 @@
   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 {
+    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);
+    }
+  }
+
+  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 = ADB_DISTANCE_EUCLIDEAN_NORMED;
+    qspec.params.npoints = 0;
+    qspec.params.ntracks = 0;
+    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[]){
--- a/audioDB_API.h	Wed Dec 31 15:44:12 2008 +0000
+++ b/audioDB_API.h	Wed Dec 31 15:44:16 2008 +0000
@@ -188,7 +188,7 @@
 
 /* query function */
 int audiodb_query(adb_ptr mydb, adb_query_ptr adbq, adb_queryresult_ptr adbqres);
-int audiodb_query_spec(adb_t *, adb_query_spec_t *, adb_query_results_t *);
+adb_query_results_t *audiodb_query_spec(adb_t *, adb_query_spec_t *);
 int audiodb_query_free_results(adb_t *, adb_query_spec_t *, adb_query_results_t *);
 
 /* database status */  
--- a/common.cpp	Wed Dec 31 15:44:12 2008 +0000
+++ b/common.cpp	Wed Dec 31 15:44:16 2008 +0000
@@ -212,3 +212,39 @@
   sprintf(prefixedName, "%s/%s", prefix, *name);
   *name = prefixedName; // side effect new name to old name
 }
+
+void audioDB::insertTimeStamps(unsigned numVectors, std::ifstream *timesFile, double *timesdata) {
+  assert(usingTimes);
+
+  unsigned numtimes = 0;
+
+  if(!timesFile->is_open()) {
+    error("problem opening times file on timestamped database", timesFileName);
+  }
+
+  double timepoint, next;
+  *timesFile >> timepoint;
+  if (timesFile->eof()) {
+    error("no entries in times file", timesFileName);
+  }
+  numtimes++;
+  do {
+    *timesFile >> next;
+    if (timesFile->eof()) {
+      break;
+    }
+    numtimes++;
+    timesdata[0] = timepoint;
+    timepoint = (timesdata[1] = next);
+    timesdata += 2;
+  } while (numtimes < numVectors + 1);
+
+  if (numtimes < numVectors + 1) {
+    error("too few timepoints in times file", timesFileName);
+  }
+
+  *timesFile >> next;
+  if (!timesFile->eof()) {
+    error("too many timepoints in times file", timesFileName);
+  }
+}
--- a/query.cpp	Wed Dec 31 15:44:12 2008 +0000
+++ b/query.cpp	Wed Dec 31 15:44:16 2008 +0000
@@ -1,6 +1,4 @@
 #include "audioDB.h"
-#include "reporter.h"
-
 #include "audioDB-internals.h"
 #include "accumulators.h"
 
@@ -18,242 +16,84 @@
   return true;
 }
 
-void audioDB::query(const char* dbName, const char* inFile, adb__queryResponse *adbQueryResponse) {
-
-  // init database tables and dbH first
-  if(query_from_key)
-    initTables(dbName);
-  else
-    initTables(dbName, inFile);
-
-  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 {
-    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);
-    }
-  }
-
-  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, dbH->numFiles);
-    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, dbH->numFiles);
-      } else {
-	reporter = new trackSequenceQueryRadReporter(trackNN, dbH->numFiles);
-      }
-      break;
-    case O2_N_SEQUENCE_QUERY:
-      if(!(qspec.refine.flags & ADB_REFINE_RADIUS)) {
-        reporter = new trackSequenceQueryNNReporter< std::less < NNresult > >(pointNN, trackNN, dbH->numFiles);
-      } else {
-	reporter = new trackSequenceQueryRadNNReporter(pointNN, trackNN, dbH->numFiles);
-      }
-      break;
-    }
-    break;
-  case O2_ONE_TO_ONE_N_SEQUENCE_QUERY:
-    qspec.params.accumulation = ADB_ACCUMULATION_ONE_TO_ONE;
-    qspec.params.distance = ADB_DISTANCE_EUCLIDEAN_NORMED;
-    qspec.params.npoints = 0;
-    qspec.params.ntracks = 0;
-    break;
-  default:
-    error("unrecognized queryType");
-  }
-
-  /* Somewhere around here is where the implementation of
-   * audiodb_query_spec() starts. */
-
-  adb_qstate_internal_t qstate;
+adb_query_results_t *audiodb_query_spec(adb_t *adb, adb_query_spec_t *qspec) {
+  adb_qstate_internal_t qstate = {0};
   qstate.allowed_keys = new std::set<std::string>;
-  if(qspec.refine.flags & ADB_REFINE_INCLUDE_KEYLIST) {
-    for(unsigned int k = 0; k < qspec.refine.include.nkeys; k++) {
-      qstate.allowed_keys->insert(qspec.refine.include.keys[k]);
+  adb_query_results_t *results;
+  if(qspec->refine.flags & ADB_REFINE_INCLUDE_KEYLIST) {
+    for(unsigned int k = 0; k < qspec->refine.include.nkeys; k++) {
+      qstate.allowed_keys->insert(qspec->refine.include.keys[k]);
     }
   } else {
     for(unsigned int k = 0; k < adb->header->numFiles; k++) {
       qstate.allowed_keys->insert((*adb->keys)[k]);
     }
   }
-  if(qspec.refine.flags & ADB_REFINE_EXCLUDE_KEYLIST) {
-    for(unsigned int k = 0; k < qspec.refine.exclude.nkeys; k++) {
-      qstate.allowed_keys->erase(qspec.refine.exclude.keys[k]);
+  if(qspec->refine.flags & ADB_REFINE_EXCLUDE_KEYLIST) {
+    for(unsigned int k = 0; k < qspec->refine.exclude.nkeys; k++) {
+      qstate.allowed_keys->erase(qspec->refine.exclude.keys[k]);
     }
   }
 
-  switch(qspec.params.distance) {
+  switch(qspec->params.distance) {
   case ADB_DISTANCE_DOT_PRODUCT:
-    switch(qspec.params.accumulation) {
+    switch(qspec->params.accumulation) {
     case ADB_ACCUMULATION_DB:
-      qstate.accumulator = new DBAccumulator<adb_result_dist_gt>(qspec.params.npoints);
+      qstate.accumulator = new DBAccumulator<adb_result_dist_gt>(qspec->params.npoints);
       break;
     case ADB_ACCUMULATION_PER_TRACK:
-      qstate.accumulator = new PerTrackAccumulator<adb_result_dist_gt>(qspec.params.npoints, qspec.params.ntracks);
+      qstate.accumulator = new PerTrackAccumulator<adb_result_dist_gt>(qspec->params.npoints, qspec->params.ntracks);
       break;
     case ADB_ACCUMULATION_ONE_TO_ONE:
       qstate.accumulator = new NearestAccumulator<adb_result_dist_gt>();
       break;
     default:
-      error("unknown accumulation");
+      goto error;
     }
     break;
   case ADB_DISTANCE_EUCLIDEAN_NORMED:
   case ADB_DISTANCE_EUCLIDEAN:
-    switch(qspec.params.accumulation) {
+    switch(qspec->params.accumulation) {
     case ADB_ACCUMULATION_DB:
-      qstate.accumulator = new DBAccumulator<adb_result_dist_lt>(qspec.params.npoints);
+      qstate.accumulator = new DBAccumulator<adb_result_dist_lt>(qspec->params.npoints);
       break;
     case ADB_ACCUMULATION_PER_TRACK:
-      qstate.accumulator = new PerTrackAccumulator<adb_result_dist_lt>(qspec.params.npoints, qspec.params.ntracks);
+      qstate.accumulator = new PerTrackAccumulator<adb_result_dist_lt>(qspec->params.npoints, qspec->params.ntracks);
       break;
     case ADB_ACCUMULATION_ONE_TO_ONE:
       qstate.accumulator = new NearestAccumulator<adb_result_dist_lt>();
       break;
     default:
-      error("unknown accumulation");
+      goto error;
     }
     break;
   default:
-    error("unknown distance function");
+    goto error;
   }
   
-  // Test for index (again) here
-  if((qspec.refine.flags & ADB_REFINE_RADIUS) && audiodb_index_exists(adb->path, qspec.refine.radius, qspec.qid.sequence_length)){ 
-    VERB_LOG(1, "Calling indexed query on database %s, radius=%f, sequence_length=%d\n", adb->path, qspec.refine.radius, qspec.qid.sequence_length);
-    if(audiodb_index_query_loop(adb, &qspec, &qstate) < 0) {
-      error("index_query_loop failed");
+  if((qspec->refine.flags & ADB_REFINE_RADIUS) && audiodb_index_exists(adb->path, qspec->refine.radius, qspec->qid.sequence_length)) {
+    if(audiodb_index_query_loop(adb, qspec, &qstate) < 0) {
+      goto error;
     }
   } else {
-    VERB_LOG(1, "Calling brute-force query on database %s\n", dbName);
-    if(audiodb_query_loop(adb, &qspec, &qstate)) {
-      error("audiodb_query_loop failed");
+    if(audiodb_query_loop(adb, qspec, &qstate)) {
+      goto error;
     }
   }
 
-  adb_query_results_t *rs = qstate.accumulator->get_points();
+  results = qstate.accumulator->get_points();
 
   delete qstate.accumulator;
   delete qstate.allowed_keys;
 
-  /* End of audiodb_query_spec() function */
+  return results;
 
-  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(fileTable, adbQueryResponse);
+ error:
+  if(qstate.accumulator)
+    delete qstate.accumulator;
+  if(qstate.allowed_keys)
+    delete qstate.allowed_keys;
+  return NULL;
 }
 
 int audiodb_query_free_results(adb_t *adb, adb_query_spec_t *spec, adb_query_results_t *rs) {
@@ -356,42 +196,6 @@
   return 1;
 }
 
-void audioDB::insertTimeStamps(unsigned numVectors, std::ifstream *timesFile, double *timesdata) {
-  assert(usingTimes);
-
-  unsigned numtimes = 0;
-
-  if(!timesFile->is_open()) {
-    error("problem opening times file on timestamped database", timesFileName);
-  }
-
-  double timepoint, next;
-  *timesFile >> timepoint;
-  if (timesFile->eof()) {
-    error("no entries in times file", timesFileName);
-  }
-  numtimes++;
-  do {
-    *timesFile >> next;
-    if (timesFile->eof()) {
-      break;
-    }
-    numtimes++;
-    timesdata[0] = timepoint;
-    timepoint = (timesdata[1] = next);
-    timesdata += 2;
-  } while (numtimes < numVectors + 1);
-
-  if (numtimes < numVectors + 1) {
-    error("too few timepoints in times file", timesFileName);
-  }
-
-  *timesFile >> next;
-  if (!timesFile->eof()) {
-    error("too many timepoints in times file", timesFileName);
-  }
-}
-
 int audiodb_track_id_datum(adb_t *adb, uint32_t track_id, adb_datum_t *d) {
   off_t track_offset = (*adb->track_offsets)[track_id];
   if(adb->header->flags & O2_FLAG_LARGE_ADB) {
--- a/reporter.h	Wed Dec 31 15:44:12 2008 +0000
+++ b/reporter.h	Wed Dec 31 15:44:16 2008 +0000
@@ -44,10 +44,9 @@
   // FIXME: this interface is a bit wacky: a relic of previous, more
   // confused times.  Really it might make sense to have separate
   // reporter classes for WS and for stdout, rather than passing this
-  // adbQueryResponse thing everywhere; the fileTable argument is
-  // there solely for convertion trackIDs into names.  -- CSR,
-  // 2007-12-10.
-  virtual void report(char *fileTable, void* adbQueryResponse) = 0;
+  // adbQueryResponse thing everywhere; the adb argument is there
+  // solely for converting trackIDs into names.  -- CSR, 2007-12-10.
+  virtual void report(adb_t *adb, void* adbQueryResponse) = 0;
 };
 
 template <class T> class pointQueryReporter : public Reporter {
@@ -55,7 +54,7 @@
   pointQueryReporter(unsigned int pointNN);
   ~pointQueryReporter();
   void add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist);
-  void report(char *fileTable, void* adbQueryResponse);
+  void report(adb_t *adb, void* adbQueryResponse);
 private:
   unsigned int pointNN;
   std::priority_queue< NNresult, std::vector< NNresult >, T> *queue;
@@ -84,7 +83,7 @@
   }
 }
 
-template <class T> void pointQueryReporter<T>::report(char *fileTable, void *adbQueryResponse) {
+template <class T> void pointQueryReporter<T>::report(adb_t *adb, void *adbQueryResponse) {
   NNresult r;
   std::vector<NNresult> v;
   unsigned int size = queue->size();
@@ -98,8 +97,8 @@
   if(adbQueryResponse==0) {
     for(rit = v.rbegin(); rit < v.rend(); rit++) {
       r = *rit;
-      if(fileTable)
-	std::cout << fileTable + r.trackID*O2_FILETABLE_ENTRY_SIZE << " ";
+      if(adb)
+	std::cout << audiodb_index_key(adb, r.trackID) << " ";
       else
 	std::cout << r.trackID << " ";
       std::cout << r.dist << " " << r.qpos << " " << r.spos << std::endl;
@@ -121,8 +120,8 @@
       response->result.Dist[k] = r.dist;
       response->result.Qpos[k] = r.qpos;
       response->result.Spos[k] = r.spos;
-      if(fileTable)
-	snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%s", fileTable+r.trackID*O2_FILETABLE_ENTRY_SIZE);
+      if(adb)
+	snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%s", audiodb_index_key(adb, r.trackID));
       else
 	snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%d", r.trackID);
     }
@@ -134,7 +133,7 @@
   trackAveragingReporter(unsigned int pointNN, unsigned int trackNN, unsigned int numFiles);
   ~trackAveragingReporter();
   void add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist);
-  void report(char *fileTable, void *adbQueryResponse);
+  void report(adb_t *adb, void *adbQueryResponse);
  protected:
   unsigned int pointNN;
   unsigned int trackNN;
@@ -165,7 +164,7 @@
   }
 }
 
-template <class T> void trackAveragingReporter<T>::report(char *fileTable, void *adbQueryResponse) {
+template <class T> void trackAveragingReporter<T>::report(adb_t *adb, void *adbQueryResponse) {
   std::priority_queue < NNresult, std::vector< NNresult>, T> result;
   for (int i = numFiles-1; i >= 0; i--) {
     unsigned int size = queues[i].size();
@@ -206,8 +205,8 @@
   if(adbQueryResponse==0) {
     for(rit = v.rbegin(); rit < v.rend(); rit++) {
       r = *rit;
-      if(fileTable)
-	std::cout << fileTable + r.trackID*O2_FILETABLE_ENTRY_SIZE << " ";
+      if(adb)
+	std::cout << audiodb_index_key(adb, r.trackID) << " ";
       else
 	std::cout << r.trackID << " ";
       std::cout << r.dist << " " << r.qpos << " " << r.spos << std::endl;
@@ -229,8 +228,8 @@
       response->result.Dist[k] = r.dist;
       response->result.Qpos[k] = r.qpos;
       response->result.Spos[k] = r.spos;
-      if(fileTable)
-	snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%s", fileTable+r.trackID*O2_FILETABLE_ENTRY_SIZE);
+      if(adb)
+	snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%s", audiodb_index_key(adb, r.trackID));
       else
 	snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%d", r.trackID);
     }
@@ -246,13 +245,13 @@
   using trackAveragingReporter<T>::pointNN;
  public:
   trackSequenceQueryNNReporter(unsigned int pointNN, unsigned int trackNN, unsigned int numFiles);
-  void report(char *fileTable, void *adbQueryResponse);
+  void report(adb_t *adb, void *adbQueryResponse);
 };
 
 template <class T> trackSequenceQueryNNReporter<T>::trackSequenceQueryNNReporter(unsigned int pointNN, unsigned int trackNN, unsigned int numFiles)
 :trackAveragingReporter<T>(pointNN, trackNN, numFiles){}
 
-template <class T> void trackSequenceQueryNNReporter<T>::report(char *fileTable, void *adbQueryResponse) {
+template <class T> void trackSequenceQueryNNReporter<T>::report(adb_t *adb, void *adbQueryResponse) {
   std::priority_queue < NNresult, std::vector< NNresult>, T> result;
   std::priority_queue< NNresult, std::vector< NNresult>, std::less<NNresult> > *point_queues 
     = new std::priority_queue< NNresult, std::vector< NNresult>, std::less<NNresult> >[numFiles];
@@ -299,11 +298,11 @@
   if(adbQueryResponse==0) {
     for(rit = v.rbegin(); rit < v.rend(); rit++) {
       r = *rit;
-      if(fileTable)
-	std::cout << fileTable + r.trackID*O2_FILETABLE_ENTRY_SIZE << " ";
+      if(adb)
+	std::cout << audiodb_index_key(adb, r.trackID) << " ";
       else
 	std::cout << r.trackID << " ";
-	std::cout << r.dist << std::endl;
+      std::cout << r.dist << std::endl;
       unsigned int qsize = point_queues[r.trackID].size();
       // Reverse the order of the points stored in point_queues
       for(unsigned int k=0; k < qsize; k++){
@@ -353,8 +352,8 @@
 	response->result.Qpos[k] = rk.qpos;
 	response->result.Spos[k] = rk.spos;
 	if(qsize){
-	  if(fileTable)
-	    snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%s", fileTable+r.trackID*O2_FILETABLE_ENTRY_SIZE);
+	  if(adb)
+	    snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%s", audiodb_index_key(adb, r.trackID));
 	  else
 	    snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%d", r.trackID);	
 	  point_queue.pop();
@@ -416,7 +415,7 @@
   trackSequenceQueryRadReporter(unsigned int trackNN, unsigned int numFiles);
   ~trackSequenceQueryRadReporter();
   void add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist);
-  void report(char *fileTable, void *adbQueryResponse);
+  void report(adb_t *adb, void *adbQueryResponse);
  protected:
   unsigned int trackNN;
   unsigned int numFiles;
@@ -463,7 +462,7 @@
   }
 }
 
-void trackSequenceQueryRadReporter::report(char *fileTable, void *adbQueryResponse) {
+void trackSequenceQueryRadReporter::report(adb_t *adb, void *adbQueryResponse) {
   std::priority_queue < Radresult, std::vector<Radresult>, std::greater<Radresult> > result;
   // KLUDGE: doing this backwards in an attempt to get the same
   // tiebreak behaviour as before.
@@ -492,8 +491,8 @@
   if(adbQueryResponse==0) {
     for(rit = v.rbegin(); rit < v.rend(); rit++) {
       r = *rit;
-      if(fileTable)
-	std::cout << fileTable + r.trackID*O2_FILETABLE_ENTRY_SIZE << " ";
+      if(adb)
+	std::cout << audiodb_index_key(adb, r.trackID) << " ";
       else
 	std::cout << r.trackID << " ";
       std::cout << r.count << std::endl;
@@ -515,8 +514,8 @@
       response->result.Dist[k] = 0;
       response->result.Qpos[k] = 0;
       response->result.Spos[k] = r.count;
-      if(fileTable)
-	snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%s", fileTable+r.trackID*O2_FILETABLE_ENTRY_SIZE);
+      if(adb)
+	snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%s", audiodb_index_key(adb, r.trackID));
       else
 	snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%d", r.trackID);
     }
@@ -532,7 +531,7 @@
   trackSequenceQueryRadNNReporter(unsigned int pointNN, unsigned int trackNN, unsigned int numFiles);
   ~trackSequenceQueryRadNNReporter();
   void add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist);
-  void report(char *fileTable, void *adbQueryResponse);
+  void report(adb_t *adb, void *adbQueryResponse);
  protected:
   unsigned int pointNN;
   unsigned int trackNN;
@@ -595,7 +594,7 @@
   }
 }
 
-void trackSequenceQueryRadNNReporter::report(char *fileTable, void *adbQueryResponse) {
+void trackSequenceQueryRadNNReporter::report(adb_t *adb, void *adbQueryResponse) {
   std::priority_queue < Radresult, std::vector<Radresult>, std::greater<Radresult> > result;
   // KLUDGE: doing this backwards in an attempt to get the same
   // tiebreak behaviour as before.
@@ -637,7 +636,7 @@
       }	
     }
     // Report
-    rep->report(fileTable, adbQueryResponse);
+    rep->report(adb, adbQueryResponse);
     // Exit
     delete[] point_queues;
     return;
@@ -651,8 +650,8 @@
   if(adbQueryResponse==0) {
     for(rit = v.rbegin(); rit < v.rend(); rit++) {
       r = *rit;
-      if(fileTable)
-	std::cout << fileTable + r.trackID*O2_FILETABLE_ENTRY_SIZE << " ";
+      if(adb)
+	std::cout << audiodb_index_key(adb, r.trackID) << " ";
       else
 	std::cout << r.trackID << " ";
       std::cout << r.count << std::endl;
@@ -705,8 +704,8 @@
 	response->result.Qpos[k] = rk.qpos;
 	response->result.Spos[k] = rk.spos;
 	if(qsize){
-	  if(fileTable)
-	    snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%s", fileTable+r.trackID*O2_FILETABLE_ENTRY_SIZE);
+	  if(adb)
+	    snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%s", audiodb_index_key(adb, r.trackID));
 	  else
 	    snprintf(response->result.Rlist[k], O2_MAXFILESTR, "%d", r.trackID);	
 	  point_queue.pop();
@@ -731,7 +730,7 @@
   trackSequenceQueryRadNNReporterOneToOne(unsigned int pointNN, unsigned int trackNN, unsigned int numFiles);
   ~trackSequenceQueryRadNNReporterOneToOne();
   void add_point(unsigned int trackID, unsigned int qpos, unsigned int spos, double dist);
-  void report(char *fileTable, void *adbQueryResponse);
+  void report(adb_t *adb, void *adbQueryResponse);
  protected:
   unsigned int pointNN;
   unsigned int trackNN;
@@ -779,7 +778,7 @@
 
 }
 
-void trackSequenceQueryRadNNReporterOneToOne::report(char *fileTable, void *adbQueryResponse) {
+void trackSequenceQueryRadNNReporterOneToOne::report(adb_t *adb, void *adbQueryResponse) {
   if(adbQueryResponse==0) {
     std::vector< NNresult >::iterator vit;
     NNresult rk;
@@ -788,8 +787,8 @@
       std::cout << rk.dist << " " 
 		<< rk.qpos << " " 
 		<< rk.spos << " ";
-      if(fileTable)
-	std::cout << fileTable + rk.trackID*O2_FILETABLE_ENTRY_SIZE << " ";
+      if(adb)
+	std::cout << audiodb_index_key(adb, rk.trackID) << " ";
       else
 	std::cout << rk.trackID << " "; 
       std::cout << std::endl;