annotate common.cpp @ 284:cacad987d785

Really finish with the sampling branch, this time merging all of it, yes, even the last revision. (The last revision was one that seeded the RNG with the current time, which is helpful when trying to get multiple independent-ish samples from the same database...)
author mas01cr
date Mon, 07 Jul 2008 08:57:06 +0000
parents 4dcb09f5fe85
children d9a88cfd4ab6
rev   line source
mas01cr@239 1 #include "audioDB.h"
mas01cr@239 2
mas01cr@239 3 #if defined(O2_DEBUG)
mas01cr@239 4 void sigterm_action(int signal, siginfo_t *info, void *context) {
mas01cr@239 5 exit(128+signal);
mas01cr@239 6 }
mas01cr@239 7
mas01cr@239 8 void sighup_action(int signal, siginfo_t *info, void *context) {
mas01cr@239 9 // FIXME: reread any configuration files
mas01cr@239 10 }
mas01cr@239 11 #endif
mas01cr@239 12
mas01cr@239 13 void audioDB::get_lock(int fd, bool exclusive) {
mas01cr@239 14 struct flock lock;
mas01cr@239 15 int status;
mas01cr@239 16
mas01cr@239 17 lock.l_type = exclusive ? F_WRLCK : F_RDLCK;
mas01cr@239 18 lock.l_whence = SEEK_SET;
mas01cr@239 19 lock.l_start = 0;
mas01cr@239 20 lock.l_len = 0; /* "the whole file" */
mas01cr@239 21
mas01cr@239 22 retry:
mas01cr@239 23 do {
mas01cr@239 24 status = fcntl(fd, F_SETLKW, &lock);
mas01cr@239 25 } while (status != 0 && errno == EINTR);
mas01cr@239 26
mas01cr@239 27 if (status) {
mas01cr@239 28 if (errno == EAGAIN) {
mas01cr@239 29 sleep(1);
mas01cr@239 30 goto retry;
mas01cr@239 31 } else {
mas01cr@239 32 error("fcntl lock error", "", "fcntl");
mas01cr@239 33 }
mas01cr@239 34 }
mas01cr@239 35 }
mas01cr@239 36
mas01cr@239 37 void audioDB::release_lock(int fd) {
mas01cr@239 38 struct flock lock;
mas01cr@239 39 int status;
mas01cr@239 40
mas01cr@239 41 lock.l_type = F_UNLCK;
mas01cr@239 42 lock.l_whence = SEEK_SET;
mas01cr@239 43 lock.l_start = 0;
mas01cr@239 44 lock.l_len = 0;
mas01cr@239 45
mas01cr@239 46 status = fcntl(fd, F_SETLKW, &lock);
mas01cr@239 47
mas01cr@239 48 if (status)
mas01cr@239 49 error("fcntl unlock error", "", "fcntl");
mas01cr@239 50 }
mas01cr@239 51
mas01cr@239 52 void audioDB::error(const char* a, const char* b, const char *sysFunc) {
mas01cr@239 53 if(isServer) {
mas01cr@239 54 /* FIXME: I think this is leaky -- we never delete err. actually
mas01cr@239 55 deleting it is tricky, though; it gets placed into some
mas01cr@239 56 soap-internal struct with uncertain extent... -- CSR,
mas01cr@239 57 2007-10-01 */
mas01cr@239 58 char *err = new char[256]; /* FIXME: overflows */
mas01cr@239 59 snprintf(err, 255, "%s: %s\n%s", a, b, sysFunc ? strerror(errno) : "");
mas01cr@239 60 /* FIXME: actually we could usefully do with a properly structured
mas01cr@239 61 type, so that we can throw separate faultstring and details.
mas01cr@239 62 -- CSR, 2007-10-01 */
mas01cr@239 63 throw(err);
mas01cr@239 64 } else {
mas01cr@239 65 std::cerr << a << ": " << b << std::endl;
mas01cr@239 66 if (sysFunc) {
mas01cr@239 67 perror(sysFunc);
mas01cr@239 68 }
mas01cr@239 69 exit(1);
mas01cr@239 70 }
mas01cr@239 71 }
mas01cr@239 72
mas01cr@284 73 void audioDB::initRNG() {
mas01cr@284 74 rng = gsl_rng_alloc(gsl_rng_mt19937);
mas01cr@284 75 if(!rng) {
mas01cr@284 76 error("could not allocate Random Number Generator");
mas01cr@284 77 }
mas01cr@284 78 /* FIXME: maybe we should use a real source of entropy? */
mas01cr@284 79 gsl_rng_set(rng, time(NULL));
mas01cr@284 80 }
mas01cr@284 81
mas01cr@239 82 void audioDB::initDBHeader(const char* dbName) {
mas01cr@239 83 if ((dbfid = open(dbName, forWrite ? O_RDWR : O_RDONLY)) < 0) {
mas01cr@239 84 error("Can't open database file", dbName, "open");
mas01cr@239 85 }
mas01cr@239 86
mas01cr@239 87 get_lock(dbfid, forWrite);
mas01cr@239 88 // Get the database header info
mas01cr@239 89 dbH = new dbTableHeaderT();
mas01cr@239 90 assert(dbH);
mas01cr@239 91
mas01cr@239 92 if(read(dbfid, (char *) dbH, O2_HEADERSIZE) != O2_HEADERSIZE) {
mas01cr@239 93 error("error reading db header", dbName, "read");
mas01cr@239 94 }
mas01cr@239 95
mas01cr@239 96 if(dbH->magic == O2_OLD_MAGIC) {
mas01cr@239 97 // FIXME: if anyone ever complains, write the program to convert
mas01cr@239 98 // from the old audioDB format to the new...
mas01cr@239 99 error("database file has old O2 header", dbName);
mas01cr@239 100 }
mas01cr@239 101
mas01cr@239 102 if(dbH->magic != O2_MAGIC) {
mas01cr@239 103 std::cerr << "expected: " << O2_MAGIC << ", got: " << dbH->magic << std::endl;
mas01cr@239 104 error("database file has incorrect header", dbName);
mas01cr@239 105 }
mas01cr@239 106
mas01cr@239 107 if(dbH->version != O2_FORMAT_VERSION) {
mas01cr@239 108 error("database file has incorrect version", dbName);
mas01cr@239 109 }
mas01cr@239 110
mas01cr@239 111 if(dbH->headerSize != O2_HEADERSIZE) {
mas01cr@239 112 error("sizeof(dbTableHeader) unexpected: platform ABI mismatch?", dbName);
mas01cr@239 113 }
mas01cr@239 114
mas01cr@239 115 CHECKED_MMAP(char *, db, 0, getpagesize());
mas01cr@239 116
mas01cr@239 117 // Make some handy tables with correct types
mas01cr@239 118 if(forWrite || (dbH->length > 0)) {
mas01cr@239 119 if(forWrite) {
mas01cr@239 120 fileTableLength = dbH->trackTableOffset - dbH->fileTableOffset;
mas01cr@239 121 trackTableLength = dbH->dataOffset - dbH->trackTableOffset;
mas01cr@239 122 dataBufLength = dbH->timesTableOffset - dbH->dataOffset;
mas01cr@239 123 timesTableLength = dbH->powerTableOffset - dbH->timesTableOffset;
mas01cr@239 124 powerTableLength = dbH->l2normTableOffset - dbH->powerTableOffset;
mas01cr@239 125 l2normTableLength = dbH->dbSize - dbH->l2normTableOffset;
mas01cr@239 126 } else {
mas01cr@256 127 fileTableLength = ALIGN_PAGE_UP(dbH->numFiles * O2_FILETABLE_ENTRY_SIZE);
mas01cr@256 128 trackTableLength = ALIGN_PAGE_UP(dbH->numFiles * O2_TRACKTABLE_ENTRY_SIZE);
mas01cr@239 129 dataBufLength = ALIGN_PAGE_UP(dbH->length);
mas01cr@239 130 timesTableLength = ALIGN_PAGE_UP(2*(dbH->length / dbH->dim));
mas01cr@239 131 powerTableLength = ALIGN_PAGE_UP(dbH->length / dbH->dim);
mas01cr@239 132 l2normTableLength = ALIGN_PAGE_UP(dbH->length / dbH->dim);
mas01cr@239 133 }
mas01cr@239 134 CHECKED_MMAP(char *, fileTable, dbH->fileTableOffset, fileTableLength);
mas01cr@239 135 CHECKED_MMAP(unsigned *, trackTable, dbH->trackTableOffset, trackTableLength);
mas01cr@239 136 /*
mas01cr@239 137 * No more mmap() for dataBuf
mas01cr@239 138 *
mas01cr@239 139 * FIXME: Actually we do do the mmap() in the two cases where it's
mas01cr@239 140 * still "needed": in pointQuery and in l2norm if dbH->length is
mas01cr@239 141 * non-zero. Removing those cases too (and deleting the dataBuf
mas01cr@239 142 * variable completely) would be cool. -- CSR, 2007-11-19
mas01cr@239 143 *
mas01cr@239 144 * CHECKED_MMAP(double *, dataBuf, dbH->dataOffset, dataBufLength);
mas01cr@239 145 */
mas01cr@239 146 CHECKED_MMAP(double *, timesTable, dbH->timesTableOffset, timesTableLength);
mas01cr@239 147 CHECKED_MMAP(double *, powerTable, dbH->powerTableOffset, powerTableLength);
mas01cr@239 148 CHECKED_MMAP(double *, l2normTable, dbH->l2normTableOffset, l2normTableLength);
mas01cr@239 149 }
mas01cr@239 150 }
mas01cr@239 151
mas01cr@239 152 void audioDB::initInputFile (const char *inFile) {
mas01cr@239 153 if (inFile) {
mas01cr@239 154 if ((infid = open(inFile, O_RDONLY)) < 0) {
mas01cr@239 155 error("can't open input file for reading", inFile, "open");
mas01cr@239 156 }
mas01cr@239 157
mas01cr@239 158 if (fstat(infid, &statbuf) < 0) {
mas01cr@239 159 error("fstat error finding size of input", inFile, "fstat");
mas01cr@239 160 }
mas01cr@239 161
mas01cr@239 162 if(dbH->dim == 0 && dbH->length == 0) { // empty database
mas01cr@239 163 // initialize with input dimensionality
mas01cr@239 164 if(read(infid, &dbH->dim, sizeof(unsigned)) != sizeof(unsigned)) {
mas01cr@239 165 error("short read of input file", inFile);
mas01cr@239 166 }
mas01cr@239 167 if(dbH->dim == 0) {
mas01cr@239 168 error("dimensionality of zero in input file", inFile);
mas01cr@239 169 }
mas01cr@239 170 } else {
mas01cr@239 171 unsigned test;
mas01cr@239 172 if(read(infid, &test, sizeof(unsigned)) != sizeof(unsigned)) {
mas01cr@239 173 error("short read of input file", inFile);
mas01cr@239 174 }
mas01cr@239 175 if(dbH->dim == 0) {
mas01cr@239 176 error("dimensionality of zero in input file", inFile);
mas01cr@239 177 }
mas01cr@239 178 if(dbH->dim != test) {
mas01cr@239 179 std::cerr << "error: expected dimension: " << dbH->dim << ", got : " << test <<std::endl;
mas01cr@239 180 error("feature dimensions do not match database table dimensions", inFile);
mas01cr@239 181 }
mas01cr@239 182 }
mas01cr@239 183
mas01cr@239 184 if ((indata = (char *) mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, infid, 0)) == (caddr_t) -1) {
mas01cr@239 185 error("mmap error for input", inFile, "mmap");
mas01cr@239 186 }
mas01cr@239 187 }
mas01cr@239 188 }
mas01cr@239 189
mas01cr@239 190 void audioDB::initTables(const char* dbName, const char* inFile = 0) {
mas01cr@284 191 /* FIXME: initRNG() really logically belongs in the audioDB
mas01cr@284 192 contructor. However, there are of the order of four constructors
mas01cr@284 193 at the moment, and more to come from API implementation. Given
mas01cr@284 194 that duplication, I think this is the least worst place to put
mas01cr@284 195 it; the assumption is that nothing which doesn't look at a
mas01cr@284 196 database will need an RNG. -- CSR, 2008-07-02 */
mas01cr@284 197 initRNG();
mas01cr@239 198 initDBHeader(dbName);
mas01cr@239 199 initInputFile(inFile);
mas01cr@239 200 }