diff dump.cpp @ 399:a65b31660804 api-inversion

Invert audioDB::dump / audiodb_dump(). No real API/ABI breakages, modulo the disappearance of audiodb_dump_withdir() (which really should have been audiodb_dump() itself from the start). There were of course ABI breakages in the previous commits. The dodgy thing in this patch is the horribleness of audiodb_dump() itself; there must be a better way of writing it, or at least abstracting some of the body into individual functional pieces. The declaration block at the top tells its own story. We also need to alter the way that audioDB::status handles the adb; rather than having a local variable, use the C++ audioDB object instance field and only open the database if necessary -- then everything has a consistent view.
author mas01cr
date Thu, 27 Nov 2008 15:19:49 +0000
parents 4ded52b104e6
children 8c7453fb5bd9
line wrap: on
line diff
--- a/dump.cpp	Thu Nov 27 15:19:47 2008 +0000
+++ b/dump.cpp	Thu Nov 27 15:19:49 2008 +0000
@@ -1,47 +1,115 @@
 #include "audioDB.h"
+extern "C" {
+#include "audioDB_API.h"
+}
 
-void audioDB::dump(const char* dbName){
-  if(!dbH) {
-    initTables(dbName, 0);
+/* We could go gcc-specific here and use typeof() instead of passing
+ * in an explicit type.  Answers on a postcard as to whether that's a
+ * good plan or not. */
+#define mmap_or_goto_error(type, var, start, length) \
+  { void *tmp = mmap(0, length, PROT_READ, MAP_SHARED, adb->fd, (start)); \
+    if(tmp == (void *) -1) { \
+      goto error; \
+    } \
+    var = (type) tmp; \
+  }
+
+#define maybe_munmap(table, length) \
+  { if(table) { \
+      munmap(table, length); \
+    } \
+  }
+
+int audiodb_dump(adb_t *adb, const char *output) {
+  char *fileTable = 0; /* key_table */
+  unsigned *trackTable = 0; /* track_size_table */
+  double *timesTable = 0; /* timestamps_table */
+  double *powerTable = 0; /* power_table */
+
+  size_t fileTableLength = 0;
+  size_t trackTableLength = 0;
+  size_t timesTableLength = 0;
+  size_t powerTableLength = 0;
+
+  char *featureFileNameTable = 0;
+  char *powerFileNameTable = 0;
+  char *timesFileNameTable = 0;
+ 
+  char cwd[PATH_MAX];
+  int directory_changed = 0;
+
+  int fLfd = 0, tLfd = 0, pLfd = 0, kLfd = 0;
+  FILE *fLFile = 0, *tLFile = 0, *pLFile = 0, *kLFile = 0;
+
+  int times, power;
+
+  char fName[256];
+  int ffd, pfd;
+  FILE *tFile;
+  unsigned pos = 0;
+  double *data_buffer;
+  size_t data_buffer_size;
+  FILE *scriptFile = 0;
+
+  unsigned nfiles = adb->header->numFiles;
+
+  if(adb->header->length > 0) {
+    fileTableLength = ALIGN_PAGE_UP(nfiles * O2_FILETABLE_ENTRY_SIZE);
+    trackTableLength = ALIGN_PAGE_UP(nfiles * O2_TRACKTABLE_ENTRY_SIZE);
+    if(!(adb->header->flags & O2_FLAG_LARGE_ADB)) {
+      off_t length = adb->header->length;
+      unsigned dim = adb->header->dim;
+      timesTableLength = ALIGN_PAGE_UP(2*length/dim);
+      powerTableLength = ALIGN_PAGE_UP(length/dim);
+    }
+
+    mmap_or_goto_error(char *, fileTable, adb->header->fileTableOffset, fileTableLength);
+    mmap_or_goto_error(unsigned *, trackTable, adb->header->trackTableOffset, trackTableLength);
+    if (adb->header->flags & O2_FLAG_LARGE_ADB) {
+      mmap_or_goto_error(char *, featureFileNameTable, adb->header->dataOffset, fileTableLength);
+      mmap_or_goto_error(char *, powerFileNameTable, adb->header->powerTableOffset, fileTableLength);
+      mmap_or_goto_error(char *, timesFileNameTable, adb->header->timesTableOffset, fileTableLength);
+    } else {
+      mmap_or_goto_error(double *, powerTable, adb->header->powerTableOffset, powerTableLength);
+      mmap_or_goto_error(double *, timesTable, adb->header->timesTableOffset, timesTableLength);
+    }
   }
 
   if((mkdir(output, S_IRWXU|S_IRWXG|S_IRWXO)) < 0) {
-    error("error making output directory", output, "mkdir");
+    goto error;
   }
 
-  char *cwd = new char[PATH_MAX];
-
   if ((getcwd(cwd, PATH_MAX)) == 0) {
-    error("error getting working directory", "", "getcwd");
+    goto error;
   }
 
+  /* FIXME: Hrm.  How does chdir(2) interact with threads?  Does each
+   * thread have its own working directory? */
   if((chdir(output)) < 0) {
-    error("error changing working directory", output, "chdir");
+    goto error;
+  }
+  directory_changed = 1;
+
+  if ((fLfd = open("featureList.txt", O_CREAT|O_RDWR|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) {
+    goto error;
   }
 
-  int fLfd, tLfd = 0, pLfd = 0, kLfd;
-  FILE *fLFile, *tLFile = 0, *pLFile = 0, *kLFile;
-
-  if ((fLfd = open("featureList.txt", O_CREAT|O_RDWR|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) {
-    error("error creating featureList file", "featureList.txt", "open");
-  }
-
-  int times = dbH->flags & O2_FLAG_TIMES;
+  times = adb->header->flags & O2_FLAG_TIMES;
   if (times) {
     if ((tLfd = open("timesList.txt", O_CREAT|O_RDWR|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) {
-      error("error creating timesList file", "timesList.txt", "open");
+      goto error;
     }
   }
 
-  int power = dbH->flags & O2_FLAG_POWER;
+  power = adb->header->flags & O2_FLAG_POWER;
   if (power) {
     if ((pLfd = open("powerList.txt", O_CREAT|O_RDWR|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) {
-      error("error creating powerList file", "powerList.txt", "open");
+      goto error;
     }
   }
 
   if ((kLfd = open("keyList.txt", O_CREAT|O_RDWR|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) {
-    error("error creating keyList file", "keyList.txt", "open");
+    goto error;
   }
   
   /* can these fail?  I sincerely hope not. */
@@ -54,69 +122,65 @@
   }
   kLFile = fdopen(kLfd, "w");
 
-  char *fName = new char[256];
-  int ffd, pfd;
-  FILE *tFile;
-  unsigned pos = 0;
-  lseek(dbfid, dbH->dataOffset, SEEK_SET);
-  double *data_buffer;
-  size_t data_buffer_size;
-  for(unsigned k = 0; k < dbH->numFiles; k++) {
+  lseek(adb->fd, adb->header->dataOffset, SEEK_SET);
+
+  for(unsigned k = 0; k < nfiles; k++) {
     fprintf(kLFile, "%s\n", fileTable + k*O2_FILETABLE_ENTRY_SIZE);
-    if(dbH->flags & O2_FLAG_LARGE_ADB) {
+    if(adb->header->flags & O2_FLAG_LARGE_ADB) {
       char *featureFileName = featureFileNameTable+k*O2_FILETABLE_ENTRY_SIZE;
+      if(*featureFileName != '/') {
+        goto error;
+      }
       fprintf(fLFile, "%s\n", featureFileName);
-      if(*featureFileName != '/') {
-	error("relative path in LARGE_ADB", featureFileName);
-      }
       if(times) {
 	char *timesFileName = timesFileNameTable + k*O2_FILETABLE_ENTRY_SIZE;
+	if(*timesFileName != '/') {
+          goto error;
+	}
 	fprintf(tLFile, "%s\n", timesFileName);
-	if(*timesFileName != '/') {
-	  error("relative path in LARGE_ADB", timesFileName);	  
-	}
       }
       if(power) {
 	char *powerFileName = powerFileNameTable + k*O2_FILETABLE_ENTRY_SIZE;
+	if(*powerFileName != '/') {
+          goto error;
+	}
 	fprintf(pLFile, "%s\n", powerFileName);
-	if(*powerFileName != '/') {
-	  error("relative path in LARGE_ADB", powerFileName);
-	}
       }
     } else {
       snprintf(fName, 256, "%05d.features", k);
       if ((ffd = open(fName, O_CREAT|O_RDWR|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) {
-	error("error creating feature file", fName, "open");
+        goto error;
       }
-      if ((write(ffd, &dbH->dim, sizeof(uint32_t))) < 0) {
-	error("error writing dimensions", fName, "write");
+      if ((write(ffd, &(adb->header->dim), sizeof(uint32_t))) < 0) {
+        goto error;
       }
       
       /* FIXME: this repeated malloc()/free() of data buffers is
 	 inefficient. */
-      data_buffer_size = trackTable[k] * dbH->dim * sizeof(double);
+      data_buffer_size = trackTable[k] * adb->header->dim * sizeof(double);
       
       {
 	void *tmp = malloc(data_buffer_size);
 	if (tmp == NULL) {
-	  error("error allocating data buffer");
+          goto error;
 	}
 	data_buffer = (double *) tmp;
       }
       
-      if ((read(dbfid, data_buffer, data_buffer_size)) != (ssize_t) data_buffer_size) {
-	error("error reading data", fName, "read");
+      if ((read(adb->fd, data_buffer, data_buffer_size)) != (ssize_t) data_buffer_size) {
+        goto error;
       }
       
       if ((write(ffd, data_buffer, data_buffer_size)) < 0) {
-	error("error writing data", fName, "write");
+        goto error;
       }
       
       free(data_buffer);
       
       fprintf(fLFile, "%s\n", fName);
       close(ffd);
-      
+      ffd = 0;
+
       if (times) {
 	snprintf(fName, 256, "%05d.times", k);
 	tFile = fopen(fName, "w");
@@ -130,6 +194,7 @@
 	  fprintf(tFile, "%.16e\n", *(timesTable + 2*pos + 2*i));
 	}
 	fprintf(tFile, "%.16e\n", *(timesTable + 2*pos + 2*trackTable[k]-1));
+        fclose(tFile);
 	
 	fprintf(tLFile, "%s\n", fName);
       }
@@ -138,16 +203,17 @@
 	uint32_t one = 1;
 	snprintf(fName, 256, "%05d.power", k);
 	if ((pfd = open(fName, O_CREAT|O_RDWR|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) {
-	  error("error creating power file", fName, "open");
+          goto error;
 	}
 	if ((write(pfd, &one, sizeof(uint32_t))) < 0) {
-	  error("error writing one", fName, "write");
+          goto error;
 	}
 	if ((write(pfd, powerTable + pos, trackTable[k] * sizeof(double))) < 0) {
-	  error("error writing data", fName, "write");
+          goto error;
 	}
 	fprintf(pLFile, "%s\n", fName);
 	close(pfd);
+        pfd = 0;
       } 
       
       pos += trackTable[k];
@@ -155,7 +221,6 @@
     }
   }
 
-  FILE *scriptFile;
   scriptFile = fopen("restore.sh", "w");
   fprintf(scriptFile, "\
 #! /bin/sh\n\
@@ -165,12 +230,12 @@
 if [ -z \"${AUDIODB}\" ]; then echo set AUDIODB variable; exit 1; fi\n\
 if [ -z \"$1\" ]; then echo usage: $0 newdb; exit 1; fi\n\n\
 \"${AUDIODB}\" -d \"$1\" -N --datasize=%d --ntracks=%d --datadim=%d\n",
-          (int) ((dbH->timesTableOffset - dbH->dataOffset) / (1024*1024)),
+          (int) ((adb->header->timesTableOffset - adb->header->dataOffset) / (1024*1024)),
           // fileTable entries (char[256]) are bigger than trackTable
           // (int), so the granularity of page aligning is finer.
-          (int) ((dbH->trackTableOffset - dbH->fileTableOffset) / O2_FILETABLE_ENTRY_SIZE),
-          (int) ceil(((double) (dbH->timesTableOffset - dbH->dataOffset)) / ((double) (dbH->dbSize - dbH->l2normTableOffset))));
-  if(dbH->flags & O2_FLAG_L2NORM) {
+          (int) ((adb->header->trackTableOffset - adb->header->fileTableOffset) / O2_FILETABLE_ENTRY_SIZE),
+          (int) ceil(((double) (adb->header->timesTableOffset - adb->header->dataOffset)) / ((double) (adb->header->dbSize - adb->header->l2normTableOffset))));
+  if(adb->header->flags & O2_FLAG_L2NORM) {
     fprintf(scriptFile, "\"${AUDIODB}\" -d \"$1\" -L\n");
   }
   if(power) {
@@ -186,10 +251,6 @@
   fprintf(scriptFile, "\n");
   fclose(scriptFile);
 
-  if((chdir(cwd)) < 0) {
-    error("error changing working directory", cwd, "chdir");
-  }
-
   fclose(fLFile);
   if(times) {
     fclose(tLFile);
@@ -198,7 +259,58 @@
     fclose(pLFile);
   }
   fclose(kLFile);
-  delete[] fName;
     
-  status(dbName);
+  maybe_munmap(fileTable, fileTableLength);
+  maybe_munmap(trackTable, trackTableLength);
+  maybe_munmap(timesTable, timesTableLength);
+  maybe_munmap(powerTable, powerTableLength);
+  maybe_munmap(featureFileNameTable, fileTableLength);
+  maybe_munmap(timesFileNameTable, fileTableLength);
+  maybe_munmap(powerFileNameTable, fileTableLength);
+
+  if((chdir(cwd)) < 0) {
+    /* don't goto error because the error handling will try to
+     * chdir() */
+    return 1;
+  }
+
+  return 0;
+
+ error:
+  if(fLFile) {
+    fclose(fLFile);
+  } else if(fLfd) {
+    close(fLfd);
+  }
+  if(tLFile) {
+    fclose(tLFile);
+  } else if(tLfd) {
+    close(fLfd);
+  }
+  if(pLFile) {
+    fclose(pLFile);
+  } else if(pLfd) {
+    close(pLfd);
+  }
+  if(kLFile) {
+    fclose(kLFile);
+  } else if(kLfd) {
+    close(kLfd);
+  }
+  if(scriptFile) {
+    fclose(scriptFile);
+  }
+
+  maybe_munmap(fileTable, fileTableLength);
+  maybe_munmap(trackTable, trackTableLength);
+  maybe_munmap(timesTable, timesTableLength);
+  maybe_munmap(powerTable, powerTableLength);
+  maybe_munmap(featureFileNameTable, fileTableLength);
+  maybe_munmap(timesFileNameTable, fileTableLength);
+  maybe_munmap(powerFileNameTable, fileTableLength);
+
+  if(directory_changed) {
+    chdir(cwd);
+  }
+  return 1;
 }