annotate common.cpp @ 512:6439cfba2524 memory-leaks

Implemented correct LSH table via compile-time switch -DLSH_DUMP_CORE_TABLES. Dumps on LSH load.
author mas01mc
date Fri, 23 Jan 2009 18:45:44 +0000
parents fbcc1303dfeb
children
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) {
mas01ik@355 53
mas01ik@355 54
mas01ik@355 55 if(isServer) {
mas01cr@370 56 /* FIXME: I think this is leaky -- we never delete err.
mas01cr@370 57 actually deleting it is tricky, though; it gets placed into
mas01cr@370 58 some soap-internal struct with uncertain extent... -- CSR,
mas01cr@370 59 2007-10-01 */
mas01cr@370 60 char *err = new char[256]; /* FIXME: overflows */
mas01cr@370 61 snprintf(err, 255, "%s: %s\n%s", a, b, sysFunc ? strerror(errno) : "");
mas01cr@370 62 /* FIXME: actually we could usefully do with a properly
mas01cr@370 63 structured type, so that we can throw separate faultstring
mas01cr@370 64 and details. -- CSR, 2007-10-01 */
mas01ik@355 65 throw(err);
mas01ik@355 66 } else if (UseApiError){
mas01ik@355 67 apierrortemp=-1;
mas01ik@355 68 throw(apierrortemp);
mas01ik@355 69 } else {
mas01ik@355 70 std::cerr << a << ": " << b << std::endl;
mas01ik@355 71 if (sysFunc) {
mas01ik@355 72 perror(sysFunc);
mas01ik@355 73 }
mas01ik@355 74 exit(1);
mas01cr@239 75 }
mas01ik@355 76
mas01cr@239 77 }
mas01cr@239 78
mas01cr@284 79 void audioDB::initRNG() {
mas01cr@284 80 rng = gsl_rng_alloc(gsl_rng_mt19937);
mas01cr@284 81 if(!rng) {
mas01cr@284 82 error("could not allocate Random Number Generator");
mas01cr@284 83 }
mas01cr@284 84 /* FIXME: maybe we should use a real source of entropy? */
mas01cr@284 85 gsl_rng_set(rng, time(NULL));
mas01cr@284 86 }
mas01cr@284 87
mas01cr@239 88 void audioDB::initDBHeader(const char* dbName) {
mas01cr@239 89 if ((dbfid = open(dbName, forWrite ? O_RDWR : O_RDONLY)) < 0) {
mas01cr@239 90 error("Can't open database file", dbName, "open");
mas01cr@239 91 }
mas01cr@239 92
mas01cr@239 93 get_lock(dbfid, forWrite);
mas01cr@239 94 // Get the database header info
mas01cr@239 95 dbH = new dbTableHeaderT();
mas01cr@239 96 assert(dbH);
mas01cr@239 97
mas01cr@239 98 if(read(dbfid, (char *) dbH, O2_HEADERSIZE) != O2_HEADERSIZE) {
mas01cr@239 99 error("error reading db header", dbName, "read");
mas01cr@239 100 }
mas01cr@239 101
mas01cr@239 102 if(dbH->magic == O2_OLD_MAGIC) {
mas01cr@239 103 // FIXME: if anyone ever complains, write the program to convert
mas01cr@239 104 // from the old audioDB format to the new...
mas01cr@239 105 error("database file has old O2 header", dbName);
mas01cr@239 106 }
mas01cr@239 107
mas01cr@239 108 if(dbH->magic != O2_MAGIC) {
mas01cr@239 109 std::cerr << "expected: " << O2_MAGIC << ", got: " << dbH->magic << std::endl;
mas01cr@239 110 error("database file has incorrect header", dbName);
mas01cr@239 111 }
mas01cr@239 112
mas01cr@239 113 if(dbH->version != O2_FORMAT_VERSION) {
mas01cr@239 114 error("database file has incorrect version", dbName);
mas01cr@239 115 }
mas01cr@239 116
mas01cr@239 117 if(dbH->headerSize != O2_HEADERSIZE) {
mas01cr@239 118 error("sizeof(dbTableHeader) unexpected: platform ABI mismatch?", dbName);
mas01cr@239 119 }
mas01cr@239 120
mas01cr@239 121 CHECKED_MMAP(char *, db, 0, getpagesize());
mas01cr@239 122
mas01cr@239 123 // Make some handy tables with correct types
mas01cr@239 124 if(forWrite || (dbH->length > 0)) {
mas01cr@239 125 if(forWrite) {
mas01cr@239 126 fileTableLength = dbH->trackTableOffset - dbH->fileTableOffset;
mas01cr@239 127 trackTableLength = dbH->dataOffset - dbH->trackTableOffset;
mas01cr@239 128 dataBufLength = dbH->timesTableOffset - dbH->dataOffset;
mas01cr@239 129 timesTableLength = dbH->powerTableOffset - dbH->timesTableOffset;
mas01cr@239 130 powerTableLength = dbH->l2normTableOffset - dbH->powerTableOffset;
mas01cr@239 131 l2normTableLength = dbH->dbSize - dbH->l2normTableOffset;
mas01cr@239 132 } else {
mas01cr@256 133 fileTableLength = ALIGN_PAGE_UP(dbH->numFiles * O2_FILETABLE_ENTRY_SIZE);
mas01cr@256 134 trackTableLength = ALIGN_PAGE_UP(dbH->numFiles * O2_TRACKTABLE_ENTRY_SIZE);
mas01mc@324 135 if( dbH->flags & O2_FLAG_LARGE_ADB ){
mas01mc@324 136 dataBufLength = ALIGN_PAGE_UP(dbH->numFiles * O2_FILETABLE_ENTRY_SIZE);
mas01mc@324 137 timesTableLength = ALIGN_PAGE_UP(dbH->numFiles * O2_FILETABLE_ENTRY_SIZE);
mas01mc@324 138 powerTableLength = ALIGN_PAGE_UP(dbH->numFiles * O2_FILETABLE_ENTRY_SIZE);
mas01mc@324 139 l2normTableLength = 0;
mas01mc@324 140 }
mas01mc@324 141 else{
mas01mc@324 142 dataBufLength = ALIGN_PAGE_UP(dbH->length);
mas01mc@324 143 timesTableLength = ALIGN_PAGE_UP(2*(dbH->length / dbH->dim));
mas01mc@324 144 powerTableLength = ALIGN_PAGE_UP(dbH->length / dbH->dim);
mas01mc@324 145 l2normTableLength = ALIGN_PAGE_UP(dbH->length / dbH->dim);
mas01mc@324 146 }
mas01cr@239 147 }
mas01cr@239 148 CHECKED_MMAP(char *, fileTable, dbH->fileTableOffset, fileTableLength);
mas01cr@239 149 CHECKED_MMAP(unsigned *, trackTable, dbH->trackTableOffset, trackTableLength);
mas01cr@239 150 /*
mas01cr@239 151 * No more mmap() for dataBuf
mas01cr@239 152 *
mas01cr@239 153 * FIXME: Actually we do do the mmap() in the two cases where it's
mas01cr@239 154 * still "needed": in pointQuery and in l2norm if dbH->length is
mas01cr@239 155 * non-zero. Removing those cases too (and deleting the dataBuf
mas01cr@239 156 * variable completely) would be cool. -- CSR, 2007-11-19
mas01cr@239 157 *
mas01cr@239 158 * CHECKED_MMAP(double *, dataBuf, dbH->dataOffset, dataBufLength);
mas01cr@239 159 */
mas01mc@324 160 if( dbH->flags & O2_FLAG_LARGE_ADB ){
mas01mc@324 161 CHECKED_MMAP(char *, featureFileNameTable, dbH->dataOffset, fileTableLength);
mas01mc@324 162 if( dbH->flags & O2_FLAG_TIMES )
mas01mc@324 163 CHECKED_MMAP(char *, timesFileNameTable, dbH->timesTableOffset, fileTableLength);
mas01mc@324 164 if( dbH->flags & O2_FLAG_POWER )
mas01mc@324 165 CHECKED_MMAP(char *, powerFileNameTable, dbH->powerTableOffset, fileTableLength);
mas01mc@324 166 }
mas01mc@324 167 else{
mas01mc@324 168 CHECKED_MMAP(double *, timesTable, dbH->timesTableOffset, timesTableLength);
mas01mc@324 169 CHECKED_MMAP(double *, powerTable, dbH->powerTableOffset, powerTableLength);
mas01mc@324 170 CHECKED_MMAP(double *, l2normTable, dbH->l2normTableOffset, l2normTableLength);
mas01mc@324 171 }
mas01cr@239 172 }
mas01mc@292 173
mas01mc@292 174 // build track offset table
mas01mc@292 175 trackOffsetTable = new off_t[dbH->numFiles];
mas01mc@292 176 Uns32T cumTrack=0;
mas01mc@292 177 for(Uns32T k = 0; k < dbH->numFiles; k++){
mas01mc@292 178 trackOffsetTable[k] = cumTrack;
mas01mc@292 179 cumTrack += trackTable[k] * dbH->dim;
mas01mc@324 180 }
mas01mc@324 181
mas01mc@324 182 // Assign correct number of point bits per track in LSH indexing / retrieval
mas01mc@500 183 lsh_n_point_bits = dbH->flags >> LSH_POINT_BITS_FIELD_POSITION;
mas01mc@324 184 if( !lsh_n_point_bits )
mas01mc@324 185 lsh_n_point_bits = O2_DEFAULT_LSH_N_POINT_BITS;
mas01cr@239 186 }
mas01cr@239 187
mas01mc@324 188 void audioDB::initInputFile (const char *inFile, bool loadData) {
mas01cr@239 189 if (inFile) {
mas01cr@239 190 if ((infid = open(inFile, O_RDONLY)) < 0) {
mas01cr@239 191 error("can't open input file for reading", inFile, "open");
mas01cr@239 192 }
mas01cr@239 193
mas01cr@239 194 if (fstat(infid, &statbuf) < 0) {
mas01cr@239 195 error("fstat error finding size of input", inFile, "fstat");
mas01cr@239 196 }
mas01cr@239 197
mas01cr@239 198 if(dbH->dim == 0 && dbH->length == 0) { // empty database
mas01cr@239 199 // initialize with input dimensionality
mas01cr@239 200 if(read(infid, &dbH->dim, sizeof(unsigned)) != sizeof(unsigned)) {
mas01cr@239 201 error("short read of input file", inFile);
mas01cr@239 202 }
mas01cr@239 203 if(dbH->dim == 0) {
mas01cr@239 204 error("dimensionality of zero in input file", inFile);
mas01cr@239 205 }
mas01cr@239 206 } else {
mas01cr@239 207 unsigned test;
mas01cr@239 208 if(read(infid, &test, sizeof(unsigned)) != sizeof(unsigned)) {
mas01cr@239 209 error("short read of input file", inFile);
mas01cr@239 210 }
mas01cr@239 211 if(dbH->dim == 0) {
mas01cr@239 212 error("dimensionality of zero in input file", inFile);
mas01cr@239 213 }
mas01cr@239 214 if(dbH->dim != test) {
mas01cr@239 215 std::cerr << "error: expected dimension: " << dbH->dim << ", got : " << test <<std::endl;
mas01cr@239 216 error("feature dimensions do not match database table dimensions", inFile);
mas01cr@239 217 }
mas01cr@239 218 }
mas01cr@239 219
mas01mc@324 220 if (loadData && ((indata = (char *) mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, infid, 0)) == (caddr_t) -1)) {
mas01cr@239 221 error("mmap error for input", inFile, "mmap");
mas01cr@239 222 }
mas01cr@239 223 }
mas01cr@239 224 }
mas01cr@239 225
mas01mc@292 226 void audioDB::initTables(const char* dbName, const char* inFile) {
mas01cr@284 227 /* FIXME: initRNG() really logically belongs in the audioDB
mas01cr@284 228 contructor. However, there are of the order of four constructors
mas01cr@284 229 at the moment, and more to come from API implementation. Given
mas01cr@284 230 that duplication, I think this is the least worst place to put
mas01cr@284 231 it; the assumption is that nothing which doesn't look at a
mas01cr@284 232 database will need an RNG. -- CSR, 2008-07-02 */
mas01cr@284 233 initRNG();
mas01cr@239 234 initDBHeader(dbName);
mas01mc@292 235 if(inFile)
mas01mc@292 236 initInputFile(inFile);
mas01cr@239 237 }
mas01mc@292 238
mas01mc@324 239 // If name is relative path, side effect name with prefix/name
mas01mc@324 240 // Do not free original pointer
mas01mc@324 241 void audioDB::prefix_name(char** const name, const char* prefix){
mas01mc@324 242 // No prefix if prefix is empty
mas01mc@324 243 if(!prefix)
mas01mc@324 244 return;
mas01mc@324 245 // Allocate new memory, keep old memory
mas01mc@324 246 assert(name && *name);
mas01mc@324 247 if (strlen(*name) + strlen(prefix) + 1 > O2_MAXFILESTR)
mas01mc@324 248 error("error: path prefix + filename too long",prefix);
mas01mc@324 249 // Do not prefix absolute path+filename
mas01mc@324 250 if(**name=='/')
mas01mc@324 251 return;
mas01mc@324 252 // OK to prefix relative path+filename
mas01mc@324 253 char* prefixedName = (char*) malloc(O2_MAXFILESTR);
mas01mc@324 254 sprintf(prefixedName, "%s/%s", prefix, *name);
mas01mc@324 255 *name = prefixedName; // side effect new name to old name
mas01mc@324 256 }