annotate audioDB.cpp @ 166:ea6936b82915

Defensive treatment of SOAP input Ensure that things that are assumed to be supplied are actually supplied, so that we will fail gracefully rather than trip over broken assumptions...
author mas01cr
date Tue, 06 Nov 2007 16:29:56 +0000
parents 5fa52830e532
children cdd441dcc9a8
rev   line source
mas01cr@0 1 #include "audioDB.h"
mas01cr@0 2
mas01cr@105 3 #if defined(O2_DEBUG)
mas01cr@104 4 void sigterm_action(int signal, siginfo_t *info, void *context) {
mas01cr@104 5 exit(128+signal);
mas01cr@104 6 }
mas01cr@104 7
mas01cr@104 8 void sighup_action(int signal, siginfo_t *info, void *context) {
mas01cr@104 9 // FIXME: reread any configuration files
mas01cr@104 10 }
mas01cr@105 11 #endif
mas01cr@0 12
mas01cr@32 13 void audioDB::error(const char* a, const char* b, const char *sysFunc) {
mas01cr@77 14 if(isServer) {
mas01cr@81 15 /* FIXME: I think this is leaky -- we never delete err. actually
mas01cr@81 16 deleting it is tricky, though; it gets placed into some
mas01cr@81 17 soap-internal struct with uncertain extent... -- CSR,
mas01cr@81 18 2007-10-01 */
mas01cr@77 19 char *err = new char[256]; /* FIXME: overflows */
mas01cr@77 20 snprintf(err, 255, "%s: %s\n%s", a, b, sysFunc ? strerror(errno) : "");
mas01cr@77 21 /* FIXME: actually we could usefully do with a properly structured
mas01cr@77 22 type, so that we can throw separate faultstring and details.
mas01cr@77 23 -- CSR, 2007-10-01 */
mas01cr@77 24 throw(err);
mas01cr@77 25 } else {
mas01cr@77 26 cerr << a << ": " << b << endl;
mas01cr@77 27 if (sysFunc) {
mas01cr@77 28 perror(sysFunc);
mas01cr@77 29 }
mas01cr@77 30 exit(1);
mas01cr@32 31 }
mas01cr@0 32 }
mas01cr@0 33
mas01cr@76 34 audioDB::audioDB(const unsigned argc, char* const argv[]): O2_AUDIODB_INITIALIZERS
mas01cr@76 35 {
mas01cr@0 36 if(processArgs(argc, argv)<0){
mas01cr@0 37 printf("No command found.\n");
mas01cr@0 38 cmdline_parser_print_version ();
mas01cr@0 39 if (strlen(gengetopt_args_info_purpose) > 0)
mas01cr@0 40 printf("%s\n", gengetopt_args_info_purpose);
mas01cr@0 41 printf("%s\n", gengetopt_args_info_usage);
mas01cr@0 42 printf("%s\n", gengetopt_args_info_help[1]);
mas01cr@0 43 printf("%s\n", gengetopt_args_info_help[2]);
mas01cr@0 44 printf("%s\n", gengetopt_args_info_help[0]);
mas01cr@151 45 error("No command found");
mas01cr@0 46 }
mas01cr@77 47
mas01cr@0 48 if(O2_ACTION(COM_SERVER))
mas01cr@0 49 startServer();
mas01cr@0 50
mas01cr@0 51 else if(O2_ACTION(COM_CREATE))
mas01cr@0 52 create(dbName);
mas01cr@0 53
mas01cr@0 54 else if(O2_ACTION(COM_INSERT))
mas01cr@0 55 insert(dbName, inFile);
mas01cr@0 56
mas01cr@0 57 else if(O2_ACTION(COM_BATCHINSERT))
mas01cr@0 58 batchinsert(dbName, inFile);
mas01cr@0 59
mas01cr@0 60 else if(O2_ACTION(COM_QUERY))
mas01cr@0 61 if(isClient)
mas01cr@0 62 ws_query(dbName, inFile, (char*)hostport);
mas01cr@0 63 else
mas01cr@76 64 query(dbName, inFile);
mas01cr@0 65
mas01cr@0 66 else if(O2_ACTION(COM_STATUS))
mas01cr@0 67 if(isClient)
mas01cr@0 68 ws_status(dbName,(char*)hostport);
mas01cr@0 69 else
mas01cr@0 70 status(dbName);
mas01cr@0 71
mas01cr@0 72 else if(O2_ACTION(COM_L2NORM))
mas01cr@0 73 l2norm(dbName);
mas01cr@0 74
mas01cr@0 75 else if(O2_ACTION(COM_DUMP))
mas01cr@0 76 dump(dbName);
mas01cr@0 77
mas01cr@0 78 else
mas01cr@0 79 error("Unrecognized command",command);
mas01cr@0 80 }
mas01cr@0 81
mas01cr@133 82 audioDB::audioDB(const unsigned argc, char* const argv[], adb__queryResponse *adbQueryResponse): O2_AUDIODB_INITIALIZERS
mas01cr@76 83 {
mas01cr@97 84 try {
mas01cr@151 85 isServer = 1; // FIXME: Hack
mas01cr@97 86 processArgs(argc, argv);
mas01cr@97 87 assert(O2_ACTION(COM_QUERY));
mas01cr@133 88 query(dbName, inFile, adbQueryResponse);
mas01cr@97 89 } catch(char *err) {
mas01cr@97 90 cleanup();
mas01cr@97 91 throw(err);
mas01cr@97 92 }
mas01cr@76 93 }
mas01cr@76 94
mas01cr@133 95 audioDB::audioDB(const unsigned argc, char* const argv[], adb__statusResponse *adbStatusResponse): O2_AUDIODB_INITIALIZERS
mas01cr@76 96 {
mas01cr@97 97 try {
mas01cr@151 98 isServer = 1; // FIXME: Hack
mas01cr@97 99 processArgs(argc, argv);
mas01cr@97 100 assert(O2_ACTION(COM_STATUS));
mas01cr@133 101 status(dbName, adbStatusResponse);
mas01cr@97 102 } catch(char *err) {
mas01cr@97 103 cleanup();
mas01cr@97 104 throw(err);
mas01cr@97 105 }
mas01cr@76 106 }
mas01cr@76 107
mas01cr@97 108 void audioDB::cleanup() {
mas01cr@122 109 cmdline_parser_free(&args_info);
mas01cr@0 110 if(indata)
mas01cr@0 111 munmap(indata,statbuf.st_size);
mas01cr@0 112 if(db)
mas01cr@128 113 munmap(db,dbH->dbSize);
mas01cr@0 114 if(dbfid>0)
mas01cr@0 115 close(dbfid);
mas01cr@0 116 if(infid>0)
mas01cr@0 117 close(infid);
mas01cr@0 118 if(dbH)
mas01cr@0 119 delete dbH;
mas01cr@0 120 }
mas01cr@0 121
mas01cr@97 122 audioDB::~audioDB(){
mas01cr@97 123 cleanup();
mas01cr@97 124 }
mas01cr@97 125
mas01cr@0 126 int audioDB::processArgs(const unsigned argc, char* const argv[]){
mas01cr@0 127
mas01cr@0 128 if(argc<2){
mas01cr@0 129 cmdline_parser_print_version ();
mas01cr@0 130 if (strlen(gengetopt_args_info_purpose) > 0)
mas01cr@0 131 printf("%s\n", gengetopt_args_info_purpose);
mas01cr@0 132 printf("%s\n", gengetopt_args_info_usage);
mas01cr@0 133 printf("%s\n", gengetopt_args_info_help[1]);
mas01cr@0 134 printf("%s\n", gengetopt_args_info_help[2]);
mas01cr@0 135 printf("%s\n", gengetopt_args_info_help[0]);
mas01cr@0 136 exit(0);
mas01cr@0 137 }
mas01cr@0 138
mas01cr@0 139 if (cmdline_parser (argc, argv, &args_info) != 0)
mas01cr@151 140 error("Error parsing command line");
mas01cr@0 141
mas01cr@0 142 if(args_info.help_given){
mas01cr@0 143 cmdline_parser_print_help();
mas01cr@0 144 exit(0);
mas01cr@0 145 }
mas01cr@0 146
mas01cr@0 147 if(args_info.verbosity_given){
mas01cr@0 148 verbosity=args_info.verbosity_arg;
mas01cr@0 149 if(verbosity<0 || verbosity>10){
mas01cr@0 150 cerr << "Warning: verbosity out of range, setting to 1" << endl;
mas01cr@0 151 verbosity=1;
mas01cr@0 152 }
mas01cr@0 153 }
mas01cr@0 154
mas01cr@129 155 if(args_info.size_given) {
mas01cr@140 156 if (args_info.size_arg < 50 || args_info.size_arg > 4000) {
mas01cr@129 157 error("Size out of range", "");
mas01cr@129 158 }
mas01cr@129 159 size = args_info.size_arg * 1000000;
mas01cr@129 160 }
mas01cr@129 161
mas01mc@17 162 if(args_info.radius_given){
mas01mc@17 163 radius=args_info.radius_arg;
mas01mc@17 164 if(radius<=0 || radius>1000000000){
mas01cr@77 165 error("radius out of range");
mas01mc@17 166 }
mas01mc@17 167 else
mas01cr@60 168 if(verbosity>3) {
mas01mc@17 169 cerr << "Setting radius to " << radius << endl;
mas01cr@60 170 }
mas01mc@17 171 }
mas01mc@17 172
mas01cr@0 173 if(args_info.SERVER_given){
mas01cr@0 174 command=COM_SERVER;
mas01cr@0 175 port=args_info.SERVER_arg;
mas01cr@0 176 if(port<100 || port > 100000)
mas01cr@0 177 error("port out of range");
mas01cr@151 178 isServer = 1;
mas01cr@105 179 #if defined(O2_DEBUG)
mas01cr@104 180 struct sigaction sa;
mas01cr@104 181 sa.sa_sigaction = sigterm_action;
mas01cr@104 182 sa.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER;
mas01cr@104 183 sigaction(SIGTERM, &sa, NULL);
mas01cr@104 184 sa.sa_sigaction = sighup_action;
mas01cr@104 185 sa.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER;
mas01cr@104 186 sigaction(SIGHUP, &sa, NULL);
mas01cr@105 187 #endif
mas01cr@0 188 return 0;
mas01cr@0 189 }
mas01cr@0 190
mas01cr@0 191 // No return on client command, find database command
mas01cr@105 192 if(args_info.client_given){
mas01cr@105 193 command=COM_CLIENT;
mas01cr@105 194 hostport=args_info.client_arg;
mas01cr@105 195 isClient=1;
mas01cr@105 196 }
mas01cr@0 197
mas01cr@105 198 if(args_info.NEW_given){
mas01cr@105 199 command=COM_CREATE;
mas01cr@105 200 dbName=args_info.database_arg;
mas01cr@105 201 return 0;
mas01cr@105 202 }
mas01cr@0 203
mas01cr@105 204 if(args_info.STATUS_given){
mas01cr@105 205 command=COM_STATUS;
mas01cr@105 206 dbName=args_info.database_arg;
mas01cr@105 207 return 0;
mas01cr@105 208 }
mas01cr@0 209
mas01cr@105 210 if(args_info.DUMP_given){
mas01cr@105 211 command=COM_DUMP;
mas01cr@105 212 dbName=args_info.database_arg;
mas01cr@131 213 output = args_info.output_arg;
mas01cr@105 214 return 0;
mas01cr@105 215 }
mas01cr@0 216
mas01cr@105 217 if(args_info.L2NORM_given){
mas01cr@105 218 command=COM_L2NORM;
mas01cr@105 219 dbName=args_info.database_arg;
mas01cr@105 220 return 0;
mas01cr@105 221 }
mas01cr@0 222
mas01cr@105 223 if(args_info.INSERT_given){
mas01cr@105 224 command=COM_INSERT;
mas01cr@105 225 dbName=args_info.database_arg;
mas01cr@105 226 inFile=args_info.features_arg;
mas01cr@105 227 if(args_info.key_given)
mas01cr@105 228 key=args_info.key_arg;
mas01cr@105 229 if(args_info.times_given){
mas01cr@105 230 timesFileName=args_info.times_arg;
mas01cr@105 231 if(strlen(timesFileName)>0){
mas01cr@105 232 if(!(timesFile = new ifstream(timesFileName,ios::in)))
mas01cr@105 233 error("Could not open times file for reading", timesFileName);
mas01cr@105 234 usingTimes=1;
mas01cr@105 235 }
mas01cr@105 236 }
mas01cr@105 237 return 0;
mas01cr@105 238 }
mas01cr@105 239
mas01cr@105 240 if(args_info.BATCHINSERT_given){
mas01cr@105 241 command=COM_BATCHINSERT;
mas01cr@105 242 dbName=args_info.database_arg;
mas01cr@105 243 inFile=args_info.featureList_arg;
mas01cr@105 244 if(args_info.keyList_given)
mas01cr@105 245 key=args_info.keyList_arg; // INCONSISTENT NO CHECK
mas01cr@0 246
mas01cr@105 247 /* TO DO: REPLACE WITH
mas01cr@0 248 if(args_info.keyList_given){
mas01mc@18 249 trackFileName=args_info.keyList_arg;
mas01mc@18 250 if(strlen(trackFileName)>0 && !(trackFile = new ifstream(trackFileName,ios::in)))
mas01mc@18 251 error("Could not open keyList file for reading",trackFileName);
mas01cr@0 252 }
mas01cr@0 253 AND UPDATE BATCHINSERT()
mas01cr@105 254 */
mas01cr@105 255
mas01cr@105 256 if(args_info.timesList_given){
mas01cr@105 257 timesFileName=args_info.timesList_arg;
mas01cr@105 258 if(strlen(timesFileName)>0){
mas01cr@105 259 if(!(timesFile = new ifstream(timesFileName,ios::in)))
mas01cr@105 260 error("Could not open timesList file for reading", timesFileName);
mas01cr@105 261 usingTimes=1;
mas01cr@105 262 }
mas01cr@105 263 }
mas01cr@105 264 return 0;
mas01cr@105 265 }
mas01cr@105 266
mas01cr@105 267 // Query command and arguments
mas01cr@105 268 if(args_info.QUERY_given){
mas01cr@105 269 command=COM_QUERY;
mas01cr@105 270 dbName=args_info.database_arg;
mas01cr@105 271 inFile=args_info.features_arg;
mas01cr@105 272
mas01cr@105 273 if(args_info.keyList_given){
mas01cr@105 274 trackFileName=args_info.keyList_arg;
mas01cr@105 275 if(strlen(trackFileName)>0 && !(trackFile = new ifstream(trackFileName,ios::in)))
mas01cr@105 276 error("Could not open keyList file for reading",trackFileName);
mas01cr@105 277 }
mas01cr@105 278
mas01cr@105 279 if(args_info.times_given){
mas01cr@105 280 timesFileName=args_info.times_arg;
mas01cr@105 281 if(strlen(timesFileName)>0){
mas01cr@105 282 if(!(timesFile = new ifstream(timesFileName,ios::in)))
mas01cr@105 283 error("Could not open times file for reading", timesFileName);
mas01cr@105 284 usingTimes=1;
mas01cr@105 285 }
mas01cr@105 286 }
mas01cr@105 287
mas01cr@105 288 // query type
mas01cr@105 289 if(strncmp(args_info.QUERY_arg, "track", MAXSTR)==0)
mas01cr@105 290 queryType=O2_TRACK_QUERY;
mas01cr@105 291 else if(strncmp(args_info.QUERY_arg, "point", MAXSTR)==0)
mas01cr@105 292 queryType=O2_POINT_QUERY;
mas01cr@105 293 else if(strncmp(args_info.QUERY_arg, "sequence", MAXSTR)==0)
mas01cr@105 294 queryType=O2_SEQUENCE_QUERY;
mas01cr@105 295 else
mas01cr@105 296 error("unsupported query type",args_info.QUERY_arg);
mas01cr@105 297
mas01cr@105 298 if(!args_info.exhaustive_flag){
mas01cr@105 299 queryPoint = args_info.qpoint_arg;
mas01cr@105 300 usingQueryPoint=1;
mas01cr@105 301 if(queryPoint<0 || queryPoint >10000)
mas01cr@105 302 error("queryPoint out of range: 0 <= queryPoint <= 10000");
mas01cr@105 303 }
mas01cr@105 304
mas01cr@105 305 pointNN = args_info.pointnn_arg;
mas01cr@105 306 if(pointNN < 1 || pointNN > 1000) {
mas01cr@105 307 error("pointNN out of range: 1 <= pointNN <= 1000");
mas01cr@105 308 }
mas01cr@105 309 trackNN = args_info.resultlength_arg;
mas01cr@105 310 if(trackNN < 1 || trackNN > 1000) {
mas01cr@105 311 error("resultlength out of range: 1 <= resultlength <= 1000");
mas01cr@105 312 }
mas01cr@105 313 sequenceLength = args_info.sequencelength_arg;
mas01cr@105 314 if(sequenceLength < 1 || sequenceLength > 1000) {
mas01cr@105 315 error("seqlen out of range: 1 <= seqlen <= 1000");
mas01cr@105 316 }
mas01cr@105 317 sequenceHop = args_info.sequencehop_arg;
mas01cr@105 318 if(sequenceHop < 1 || sequenceHop > 1000) {
mas01cr@105 319 error("seqhop out of range: 1 <= seqhop <= 1000");
mas01cr@105 320 }
mas01cr@105 321 return 0;
mas01cr@105 322 }
mas01cr@105 323 return -1; // no command found
mas01cr@0 324 }
mas01cr@0 325
mas01cr@30 326 void audioDB::get_lock(int fd, bool exclusive) {
mas01cr@30 327 struct flock lock;
mas01cr@30 328 int status;
mas01cr@30 329
mas01cr@30 330 lock.l_type = exclusive ? F_WRLCK : F_RDLCK;
mas01cr@30 331 lock.l_whence = SEEK_SET;
mas01cr@30 332 lock.l_start = 0;
mas01cr@30 333 lock.l_len = 0; /* "the whole file" */
mas01cr@30 334
mas01cr@30 335 retry:
mas01cr@30 336 do {
mas01cr@30 337 status = fcntl(fd, F_SETLKW, &lock);
mas01cr@30 338 } while (status != 0 && errno == EINTR);
mas01cr@30 339
mas01cr@30 340 if (status) {
mas01cr@30 341 if (errno == EAGAIN) {
mas01cr@30 342 sleep(1);
mas01cr@30 343 goto retry;
mas01cr@30 344 } else {
mas01cr@32 345 error("fcntl lock error", "", "fcntl");
mas01cr@30 346 }
mas01cr@30 347 }
mas01cr@30 348 }
mas01cr@30 349
mas01cr@30 350 void audioDB::release_lock(int fd) {
mas01cr@30 351 struct flock lock;
mas01cr@30 352 int status;
mas01cr@30 353
mas01cr@30 354 lock.l_type = F_UNLCK;
mas01cr@30 355 lock.l_whence = SEEK_SET;
mas01cr@30 356 lock.l_start = 0;
mas01cr@30 357 lock.l_len = 0;
mas01cr@30 358
mas01cr@30 359 status = fcntl(fd, F_SETLKW, &lock);
mas01cr@30 360
mas01cr@30 361 if (status)
mas01cr@32 362 error("fcntl unlock error", "", "fcntl");
mas01cr@30 363 }
mas01cr@30 364
mas01cr@120 365 /* Make a new database.
mas01cr@120 366
mas01cr@120 367 The database consists of:
mas01cr@120 368
mas01cr@120 369 * a header (see dbTableHeader struct definition);
mas01cr@120 370 * keyTable: list of keys of tracks;
mas01cr@120 371 * trackTable: Maps implicit feature index to a feature vector
mas01cr@120 372 matrix (sizes of tracks)
mas01cr@120 373 * featureTable: Lots of doubles;
mas01cr@120 374 * timesTable: time points for each feature vector;
mas01cr@120 375 * l2normTable: squared l2norms for each feature vector.
mas01cr@120 376 */
mas01cr@0 377 void audioDB::create(const char* dbName){
mas01cr@31 378 if ((dbfid = open (dbName, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0)
mas01cr@32 379 error("Can't create database file", dbName, "open");
mas01cr@30 380 get_lock(dbfid, 1);
mas01cr@0 381
mas01cr@0 382 // go to the location corresponding to the last byte
mas01cr@129 383 if (lseek (dbfid, size - 1, SEEK_SET) == -1)
mas01cr@32 384 error("lseek error in db file", "", "lseek");
mas01cr@0 385
mas01cr@0 386 // write a dummy byte at the last location
mas01cr@0 387 if (write (dbfid, "", 1) != 1)
mas01cr@32 388 error("write error", "", "write");
mas01cr@0 389
mas01cr@0 390 // mmap the output file
mas01cr@60 391 if(verbosity) {
mas01cr@0 392 cerr << "header size:" << O2_HEADERSIZE << endl;
mas01cr@60 393 }
mas01cr@129 394 if ((db = (char*) mmap(0, size, PROT_READ | PROT_WRITE,
mas01cr@0 395 MAP_SHARED, dbfid, 0)) == (caddr_t) -1)
mas01cr@32 396 error("mmap error for creating database", "", "mmap");
mas01cr@0 397
mas01cr@0 398 dbH = new dbTableHeaderT();
mas01cr@0 399 assert(dbH);
mas01cr@0 400
mas01cr@140 401 unsigned int maxfiles = (unsigned int) rint((double) O2_MAXFILES * (double) size / (double) O2_DEFAULTDBSIZE);
mas01cr@140 402
mas01cr@0 403 // Initialize header
mas01cr@108 404 dbH->magic = O2_MAGIC;
mas01cr@108 405 dbH->version = O2_FORMAT_VERSION;
mas01cr@108 406 dbH->numFiles = 0;
mas01cr@108 407 dbH->dim = 0;
mas01cr@108 408 dbH->flags = 0;
mas01cr@108 409 dbH->length = 0;
mas01cr@108 410 dbH->fileTableOffset = ALIGN_UP(O2_HEADERSIZE, 8);
mas01cr@140 411 dbH->trackTableOffset = ALIGN_UP(dbH->fileTableOffset + O2_FILETABLESIZE*maxfiles, 8);
mas01cr@140 412 dbH->dataOffset = ALIGN_UP(dbH->trackTableOffset + O2_TRACKTABLESIZE*maxfiles, 8);
mas01cr@140 413 dbH->l2normTableOffset = ALIGN_DOWN(size - maxfiles*O2_MEANNUMVECTORS*sizeof(double), 8);
mas01cr@140 414 dbH->timesTableOffset = ALIGN_DOWN(dbH->l2normTableOffset - maxfiles*O2_MEANNUMVECTORS*sizeof(double), 8);
mas01cr@129 415 dbH->dbSize = size;
mas01cr@0 416
mas01cr@0 417 memcpy (db, dbH, O2_HEADERSIZE);
mas01cr@60 418 if(verbosity) {
mas01cr@0 419 cerr << COM_CREATE << " " << dbName << endl;
mas01cr@60 420 }
mas01cr@0 421 }
mas01cr@0 422
mas01cr@0 423
mas01cr@0 424 void audioDB::drop(){
mas01cr@108 425 // FIXME: drop something? Should we even allow this?
mas01cr@0 426 }
mas01cr@0 427
mas01cr@120 428 void audioDB::initDBHeader(const char* dbName, bool forWrite) {
mas01cr@106 429 if ((dbfid = open(dbName, forWrite ? O_RDWR : O_RDONLY)) < 0) {
mas01cr@32 430 error("Can't open database file", dbName, "open");
mas01cr@106 431 }
mas01cr@120 432
mas01cr@30 433 get_lock(dbfid, forWrite);
mas01cr@0 434 // Get the database header info
mas01cr@0 435 dbH = new dbTableHeaderT();
mas01cr@0 436 assert(dbH);
mas01cr@0 437
mas01cr@106 438 if(read(dbfid, (char *) dbH, O2_HEADERSIZE) != O2_HEADERSIZE) {
mas01cr@106 439 error("error reading db header", dbName, "read");
mas01cr@106 440 }
mas01cr@0 441
mas01cr@108 442 if(dbH->magic == O2_OLD_MAGIC) {
mas01cr@108 443 // FIXME: if anyone ever complains, write the program to convert
mas01cr@108 444 // from the old audioDB format to the new...
mas01cr@108 445 error("database file has old O2 header", dbName);
mas01cr@108 446 }
mas01cr@0 447
mas01cr@106 448 if(dbH->magic != O2_MAGIC) {
mas01cr@106 449 cerr << "expected: " << O2_MAGIC << ", got: " << dbH->magic << endl;
mas01cr@108 450 error("database file has incorrect header", dbName);
mas01cr@108 451 }
mas01cr@108 452
mas01cr@108 453 if(dbH->version != O2_FORMAT_VERSION) {
mas01cr@108 454 error("database file has incorect version", dbName);
mas01cr@0 455 }
mas01cr@0 456
mas01cr@128 457 // FIXME: when changing file format version, remove this workaround.
mas01cr@128 458 if(dbH->dbSize == 0) {
mas01cr@128 459 dbH->dbSize = O2_DEFAULTDBSIZE;
mas01cr@128 460 }
mas01cr@128 461
mas01cr@120 462 // mmap the database file
mas01cr@128 463 if ((db = (char*) mmap(0, dbH->dbSize, PROT_READ | (forWrite ? PROT_WRITE : 0),
mas01cr@120 464 MAP_SHARED, dbfid, 0)) == (caddr_t) -1)
mas01cr@120 465 error("mmap error for initting tables of database", "", "mmap");
mas01cr@120 466
mas01cr@120 467 // Make some handy tables with correct types
mas01cr@120 468 fileTable = (char *) (db + dbH->fileTableOffset);
mas01cr@120 469 trackTable = (unsigned *) (db + dbH->trackTableOffset);
mas01cr@120 470 dataBuf = (double *) (db + dbH->dataOffset);
mas01cr@120 471 l2normTable = (double *) (db + dbH->l2normTableOffset);
mas01cr@120 472 timesTable = (double *) (db + dbH->timesTableOffset);
mas01cr@120 473 }
mas01cr@120 474
mas01cr@120 475 void audioDB::initTables(const char* dbName, bool forWrite, const char* inFile = 0) {
mas01cr@120 476
mas01cr@120 477 initDBHeader(dbName, forWrite);
mas01cr@120 478
mas01cr@120 479 // open the input file
mas01cr@120 480 if (inFile && (infid = open(inFile, O_RDONLY)) < 0) {
mas01cr@120 481 error("can't open input file for reading", inFile, "open");
mas01cr@120 482 }
mas01cr@120 483 // find size of input file
mas01cr@120 484 if (inFile && fstat(infid, &statbuf) < 0) {
mas01cr@120 485 error("fstat error finding size of input", inFile, "fstat");
mas01cr@120 486 }
mas01cr@0 487 if(inFile)
mas01cr@106 488 if(dbH->dim == 0 && dbH->length == 0) // empty database
mas01cr@106 489 // initialize with input dimensionality
mas01cr@106 490 read(infid, &dbH->dim, sizeof(unsigned));
mas01cr@0 491 else {
mas01cr@0 492 unsigned test;
mas01cr@106 493 read(infid, &test, sizeof(unsigned));
mas01cr@106 494 if(dbH->dim != test) {
mas01cr@106 495 cerr << "error: expected dimension: " << dbH->dim << ", got : " << test <<endl;
mas01cr@0 496 error("feature dimensions do not match database table dimensions");
mas01cr@0 497 }
mas01cr@0 498 }
mas01cr@0 499
mas01cr@0 500 // mmap the input file
mas01cr@0 501 if (inFile && (indata = (char*)mmap (0, statbuf.st_size, PROT_READ, MAP_SHARED, infid, 0))
mas01cr@0 502 == (caddr_t) -1)
mas01cr@106 503 error("mmap error for input", inFile, "mmap");
mas01cr@0 504 }
mas01cr@0 505
mas01cr@0 506 void audioDB::insert(const char* dbName, const char* inFile){
mas01cr@0 507
mas01cr@27 508 initTables(dbName, 1, inFile);
mas01cr@0 509
mas01cr@0 510 if(!usingTimes && (dbH->flags & O2_FLAG_TIMES))
mas01cr@0 511 error("Must use timestamps with timestamped database","use --times");
mas01cr@0 512
mas01cr@0 513 // Check that there is room for at least 1 more file
mas01cr@0 514 if((char*)timesTable<((char*)dataBuf+dbH->length+statbuf.st_size-sizeof(int)))
mas01cr@0 515 error("No more room in database","insert failed: reason database is full.");
mas01cr@0 516
mas01cr@0 517 if(!key)
mas01cr@0 518 key=inFile;
mas01cr@0 519 // Linear scan of filenames check for pre-existing feature
mas01cr@0 520 unsigned alreadyInserted=0;
mas01cr@0 521 for(unsigned k=0; k<dbH->numFiles; k++)
mas01cr@0 522 if(strncmp(fileTable + k*O2_FILETABLESIZE, key, strlen(key))==0){
mas01cr@0 523 alreadyInserted=1;
mas01cr@0 524 break;
mas01cr@0 525 }
mas01cr@0 526
mas01cr@0 527 if(alreadyInserted){
mas01cr@60 528 if(verbosity) {
mas01cr@0 529 cerr << "Warning: key already exists in database, ignoring: " <<inFile << endl;
mas01cr@60 530 }
mas01cr@0 531 return;
mas01cr@0 532 }
mas01cr@0 533
mas01mc@18 534 // Make a track index table of features to file indexes
mas01cr@0 535 unsigned numVectors = (statbuf.st_size-sizeof(int))/(sizeof(double)*dbH->dim);
mas01cr@0 536 if(!numVectors){
mas01cr@60 537 if(verbosity) {
mas01cr@0 538 cerr << "Warning: ignoring zero-length feature vector file:" << key << endl;
mas01cr@60 539 }
mas01cr@0 540 // CLEAN UP
mas01cr@0 541 munmap(indata,statbuf.st_size);
mas01cr@128 542 munmap(db,dbH->dbSize);
mas01cr@0 543 close(infid);
mas01cr@0 544 return;
mas01cr@0 545 }
mas01cr@0 546
mas01cr@0 547 strncpy(fileTable + dbH->numFiles*O2_FILETABLESIZE, key, strlen(key));
mas01cr@0 548
mas01cr@0 549 unsigned insertoffset = dbH->length;// Store current state
mas01cr@0 550
mas01cr@0 551 // Check times status and insert times from file
mas01cr@0 552 unsigned timesoffset=insertoffset/(dbH->dim*sizeof(double));
mas01cr@0 553 double* timesdata=timesTable+timesoffset;
mas01cr@0 554 assert(timesdata+numVectors<l2normTable);
mas01cr@0 555 insertTimeStamps(numVectors, timesFile, timesdata);
mas01cr@0 556
mas01cr@0 557 // Increment file count
mas01cr@0 558 dbH->numFiles++;
mas01cr@0 559
mas01cr@0 560 // Update Header information
mas01cr@0 561 dbH->length+=(statbuf.st_size-sizeof(int));
mas01cr@0 562
mas01cr@0 563 // Copy the header back to the database
mas01cr@0 564 memcpy (db, dbH, sizeof(dbTableHeaderT));
mas01cr@0 565
mas01mc@18 566 // Update track to file index map
mas01mc@18 567 //memcpy (db+trackTableOffset+(dbH->numFiles-1)*sizeof(unsigned), &numVectors, sizeof(unsigned));
mas01mc@18 568 memcpy (trackTable+dbH->numFiles-1, &numVectors, sizeof(unsigned));
mas01cr@0 569
mas01cr@0 570 // Update the feature database
mas01cr@108 571 memcpy (db+dbH->dataOffset+insertoffset, indata+sizeof(int), statbuf.st_size-sizeof(int));
mas01cr@0 572
mas01cr@0 573 // Norm the vectors on input if the database is already L2 normed
mas01cr@0 574 if(dbH->flags & O2_FLAG_L2NORM)
mas01cr@108 575 unitNormAndInsertL2((double*)(db+dbH->dataOffset+insertoffset), dbH->dim, numVectors, 1); // append
mas01cr@0 576
mas01cr@0 577 // Report status
mas01cr@0 578 status(dbName);
mas01cr@60 579 if(verbosity) {
mas01cr@0 580 cerr << COM_INSERT << " " << dbName << " " << numVectors << " vectors "
mas01cr@0 581 << (statbuf.st_size-sizeof(int)) << " bytes." << endl;
mas01cr@60 582 }
mas01cr@0 583
mas01cr@0 584 // CLEAN UP
mas01cr@0 585 munmap(indata,statbuf.st_size);
mas01cr@0 586 close(infid);
mas01cr@0 587 }
mas01cr@0 588
mas01cr@0 589 void audioDB::insertTimeStamps(unsigned numVectors, ifstream* timesFile, double* timesdata){
mas01cr@0 590 unsigned numtimes=0;
mas01cr@0 591 if(usingTimes){
mas01cr@0 592 if(!(dbH->flags & O2_FLAG_TIMES) && !dbH->numFiles)
mas01cr@0 593 dbH->flags=dbH->flags|O2_FLAG_TIMES;
mas01cr@0 594 else if(!(dbH->flags&O2_FLAG_TIMES)){
mas01cr@0 595 cerr << "Warning: timestamp file used with non time-stamped database: ignoring timestamps" << endl;
mas01cr@0 596 usingTimes=0;
mas01cr@0 597 }
mas01cr@0 598
mas01cr@0 599 if(!timesFile->is_open()){
mas01cr@0 600 if(dbH->flags & O2_FLAG_TIMES){
mas01cr@0 601 munmap(indata,statbuf.st_size);
mas01cr@128 602 munmap(db,dbH->dbSize);
mas01cr@0 603 error("problem opening times file on timestamped database",timesFileName);
mas01cr@0 604 }
mas01cr@0 605 else{
mas01cr@0 606 cerr << "Warning: problem opening times file. But non-timestamped database, so ignoring times file." << endl;
mas01cr@0 607 usingTimes=0;
mas01cr@0 608 }
mas01cr@0 609 }
mas01cr@0 610
mas01cr@0 611 // Process time file
mas01cr@0 612 if(usingTimes){
mas01cr@0 613 do{
mas01cr@0 614 *timesFile>>*timesdata++;
mas01cr@0 615 if(timesFile->eof())
mas01cr@0 616 break;
mas01cr@0 617 numtimes++;
mas01cr@0 618 }while(!timesFile->eof() && numtimes<numVectors);
mas01cr@0 619 if(!timesFile->eof()){
mas01cr@0 620 double dummy;
mas01cr@0 621 do{
mas01cr@0 622 *timesFile>>dummy;
mas01cr@0 623 if(timesFile->eof())
mas01cr@0 624 break;
mas01cr@0 625 numtimes++;
mas01cr@0 626 }while(!timesFile->eof());
mas01cr@0 627 }
mas01cr@0 628 if(numtimes<numVectors || numtimes>numVectors+2){
mas01cr@0 629 munmap(indata,statbuf.st_size);
mas01cr@128 630 munmap(db,dbH->dbSize);
mas01cr@0 631 close(infid);
mas01cr@0 632 cerr << "expected " << numVectors << " found " << numtimes << endl;
mas01cr@0 633 error("Times file is incorrect length for features file",inFile);
mas01cr@0 634 }
mas01cr@60 635 if(verbosity>2) {
mas01cr@0 636 cerr << "numtimes: " << numtimes << endl;
mas01cr@60 637 }
mas01cr@0 638 }
mas01cr@0 639 }
mas01cr@0 640 }
mas01cr@0 641
mas01cr@120 642 void audioDB::batchinsert(const char* dbName, const char* inFile) {
mas01cr@0 643
mas01cr@120 644 initDBHeader(dbName, true);
mas01cr@0 645
mas01cr@0 646 if(!key)
mas01cr@0 647 key=inFile;
mas01cr@0 648 ifstream *filesIn = 0;
mas01cr@0 649 ifstream *keysIn = 0;
mas01cr@0 650 ifstream* thisTimesFile = 0;
mas01cr@0 651
mas01cr@0 652 if(!(filesIn = new ifstream(inFile)))
mas01cr@0 653 error("Could not open batch in file", inFile);
mas01cr@0 654 if(key && key!=inFile)
mas01cr@0 655 if(!(keysIn = new ifstream(key)))
mas01cr@0 656 error("Could not open batch key file",key);
mas01cr@0 657
mas01cr@0 658 if(!usingTimes && (dbH->flags & O2_FLAG_TIMES))
mas01cr@0 659 error("Must use timestamps with timestamped database","use --times");
mas01cr@0 660
mas01cr@0 661 unsigned totalVectors=0;
mas01cr@0 662 char *thisKey = new char[MAXSTR];
mas01cr@0 663 char *thisFile = new char[MAXSTR];
mas01cr@0 664 char *thisTimesFileName = new char[MAXSTR];
mas01cr@120 665
mas01cr@0 666 do{
mas01cr@0 667 filesIn->getline(thisFile,MAXSTR);
mas01cr@0 668 if(key && key!=inFile)
mas01cr@0 669 keysIn->getline(thisKey,MAXSTR);
mas01cr@0 670 else
mas01cr@0 671 thisKey = thisFile;
mas01cr@0 672 if(usingTimes)
mas01cr@0 673 timesFile->getline(thisTimesFileName,MAXSTR);
mas01cr@0 674
mas01cr@0 675 if(filesIn->eof())
mas01cr@0 676 break;
mas01cr@0 677
mas01cr@0 678 // open the input file
mas01cr@0 679 if (thisFile && (infid = open (thisFile, O_RDONLY)) < 0)
mas01cr@32 680 error("can't open feature file for reading", thisFile, "open");
mas01cr@0 681
mas01cr@0 682 // find size of input file
mas01cr@0 683 if (thisFile && fstat (infid,&statbuf) < 0)
mas01cr@32 684 error("fstat error finding size of input", "", "fstat");
mas01cr@0 685
mas01cr@0 686 // Check that there is room for at least 1 more file
mas01cr@0 687 if((char*)timesTable<((char*)dataBuf+(dbH->length+statbuf.st_size-sizeof(int))))
mas01cr@0 688 error("No more room in database","insert failed: reason database is full.");
mas01cr@0 689
mas01cr@0 690 if(thisFile)
mas01cr@0 691 if(dbH->dim==0 && dbH->length==0) // empty database
mas01cr@0 692 read(infid,&dbH->dim,sizeof(unsigned)); // initialize with input dimensionality
mas01cr@0 693 else {
mas01cr@0 694 unsigned test;
mas01cr@0 695 read(infid,&test,sizeof(unsigned));
mas01cr@0 696 if(dbH->dim!=test){
mas01cr@0 697 cerr << "error: expected dimension: " << dbH->dim << ", got :" << test <<endl;
mas01cr@0 698 error("feature dimensions do not match database table dimensions");
mas01cr@0 699 }
mas01cr@0 700 }
mas01cr@0 701
mas01cr@0 702 // mmap the input file
mas01cr@0 703 if (thisFile && (indata = (char*)mmap (0, statbuf.st_size, PROT_READ, MAP_SHARED, infid, 0))
mas01cr@0 704 == (caddr_t) -1)
mas01cr@32 705 error("mmap error for input", "", "mmap");
mas01cr@0 706
mas01cr@0 707
mas01cr@0 708 // Linear scan of filenames check for pre-existing feature
mas01cr@0 709 unsigned alreadyInserted=0;
mas01cr@0 710
mas01cr@0 711 for(unsigned k=0; k<dbH->numFiles; k++)
mas01cr@0 712 if(strncmp(fileTable + k*O2_FILETABLESIZE, thisKey, strlen(thisKey))==0){
mas01cr@0 713 alreadyInserted=1;
mas01cr@0 714 break;
mas01cr@0 715 }
mas01cr@0 716
mas01cr@0 717 if(alreadyInserted){
mas01cr@60 718 if(verbosity) {
mas01cr@0 719 cerr << "Warning: key already exists in database:" << thisKey << endl;
mas01cr@60 720 }
mas01cr@0 721 }
mas01cr@0 722 else{
mas01cr@0 723
mas01mc@18 724 // Make a track index table of features to file indexes
mas01cr@0 725 unsigned numVectors = (statbuf.st_size-sizeof(int))/(sizeof(double)*dbH->dim);
mas01cr@0 726 if(!numVectors){
mas01cr@60 727 if(verbosity) {
mas01cr@0 728 cerr << "Warning: ignoring zero-length feature vector file:" << thisKey << endl;
mas01cr@60 729 }
mas01cr@0 730 }
mas01cr@0 731 else{
mas01cr@0 732 if(usingTimes){
mas01cr@0 733 if(timesFile->eof())
mas01cr@0 734 error("not enough timestamp files in timesList");
mas01cr@0 735 thisTimesFile=new ifstream(thisTimesFileName,ios::in);
mas01cr@0 736 if(!thisTimesFile->is_open())
mas01cr@0 737 error("Cannot open timestamp file",thisTimesFileName);
mas01cr@0 738 unsigned insertoffset=dbH->length;
mas01cr@0 739 unsigned timesoffset=insertoffset/(dbH->dim*sizeof(double));
mas01cr@0 740 double* timesdata=timesTable+timesoffset;
mas01cr@0 741 assert(timesdata+numVectors<l2normTable);
mas01cr@0 742 insertTimeStamps(numVectors,thisTimesFile,timesdata);
mas01cr@0 743 if(thisTimesFile)
mas01cr@0 744 delete thisTimesFile;
mas01cr@0 745 }
mas01cr@0 746
mas01cr@0 747 strncpy(fileTable + dbH->numFiles*O2_FILETABLESIZE, thisKey, strlen(thisKey));
mas01cr@0 748
mas01cr@0 749 unsigned insertoffset = dbH->length;// Store current state
mas01cr@0 750
mas01cr@0 751 // Increment file count
mas01cr@0 752 dbH->numFiles++;
mas01cr@0 753
mas01cr@0 754 // Update Header information
mas01cr@0 755 dbH->length+=(statbuf.st_size-sizeof(int));
mas01cr@0 756 // Copy the header back to the database
mas01cr@0 757 memcpy (db, dbH, sizeof(dbTableHeaderT));
mas01cr@0 758
mas01mc@18 759 // Update track to file index map
mas01mc@18 760 //memcpy (db+trackTableOffset+(dbH->numFiles-1)*sizeof(unsigned), &numVectors, sizeof(unsigned));
mas01mc@18 761 memcpy (trackTable+dbH->numFiles-1, &numVectors, sizeof(unsigned));
mas01cr@0 762
mas01cr@0 763 // Update the feature database
mas01cr@108 764 memcpy (db+dbH->dataOffset+insertoffset, indata+sizeof(int), statbuf.st_size-sizeof(int));
mas01cr@0 765
mas01cr@0 766 // Norm the vectors on input if the database is already L2 normed
mas01cr@0 767 if(dbH->flags & O2_FLAG_L2NORM)
mas01cr@108 768 unitNormAndInsertL2((double*)(db+dbH->dataOffset+insertoffset), dbH->dim, numVectors, 1); // append
mas01cr@0 769
mas01cr@0 770 totalVectors+=numVectors;
mas01cr@0 771 }
mas01cr@0 772 }
mas01cr@0 773 // CLEAN UP
mas01cr@0 774 munmap(indata,statbuf.st_size);
mas01cr@0 775 close(infid);
mas01cr@0 776 }while(!filesIn->eof());
mas01mc@12 777
mas01cr@60 778 if(verbosity) {
mas01cr@0 779 cerr << COM_BATCHINSERT << " " << dbName << " " << totalVectors << " vectors "
mas01cr@0 780 << totalVectors*dbH->dim*sizeof(double) << " bytes." << endl;
mas01cr@60 781 }
mas01cr@0 782
mas01cr@0 783 // Report status
mas01cr@0 784 status(dbName);
mas01cr@0 785 }
mas01cr@0 786
mas01cr@76 787 // FIXME: this can't propagate the sequence length argument (used for
mas01cr@76 788 // dudCount). See adb__status() definition for the other half of
mas01cr@76 789 // this. -- CSR, 2007-10-01
mas01cr@0 790 void audioDB::ws_status(const char*dbName, char* hostport){
mas01cr@0 791 struct soap soap;
mas01cr@133 792 adb__statusResponse adbStatusResponse;
mas01cr@0 793
mas01cr@0 794 // Query an existing adb database
mas01cr@0 795 soap_init(&soap);
mas01cr@133 796 if(soap_call_adb__status(&soap,hostport,NULL,(char*)dbName,adbStatusResponse)==SOAP_OK) {
mas01cr@133 797 cout << "numFiles = " << adbStatusResponse.result.numFiles << endl;
mas01cr@133 798 cout << "dim = " << adbStatusResponse.result.dim << endl;
mas01cr@133 799 cout << "length = " << adbStatusResponse.result.length << endl;
mas01cr@133 800 cout << "dudCount = " << adbStatusResponse.result.dudCount << endl;
mas01cr@133 801 cout << "nullCount = " << adbStatusResponse.result.nullCount << endl;
mas01cr@133 802 cout << "flags = " << adbStatusResponse.result.flags << endl;
mas01cr@76 803 } else {
mas01cr@0 804 soap_print_fault(&soap,stderr);
mas01cr@76 805 }
mas01cr@0 806
mas01cr@0 807 soap_destroy(&soap);
mas01cr@0 808 soap_end(&soap);
mas01cr@0 809 soap_done(&soap);
mas01cr@0 810 }
mas01cr@0 811
mas01mc@18 812 void audioDB::ws_query(const char*dbName, const char *trackKey, const char* hostport){
mas01cr@0 813 struct soap soap;
mas01cr@133 814 adb__queryResponse adbQueryResponse;
mas01cr@0 815
mas01cr@0 816 soap_init(&soap);
mas01cr@0 817 if(soap_call_adb__query(&soap,hostport,NULL,
mas01mc@18 818 (char*)dbName,(char*)trackKey,(char*)trackFileName,(char*)timesFileName,
mas01cr@133 819 queryType, queryPoint, pointNN, trackNN, sequenceLength, adbQueryResponse)==SOAP_OK){
mas01cr@133 820 //std::cerr << "result list length:" << adbQueryResponse.result.__sizeRlist << std::endl;
mas01cr@133 821 for(int i=0; i<adbQueryResponse.result.__sizeRlist; i++)
mas01cr@133 822 std::cout << adbQueryResponse.result.Rlist[i] << " " << adbQueryResponse.result.Dist[i]
mas01cr@133 823 << " " << adbQueryResponse.result.Qpos[i] << " " << adbQueryResponse.result.Spos[i] << std::endl;
mas01cr@0 824 }
mas01cr@0 825 else
mas01cr@0 826 soap_print_fault(&soap,stderr);
mas01cr@0 827
mas01cr@0 828 soap_destroy(&soap);
mas01cr@0 829 soap_end(&soap);
mas01cr@0 830 soap_done(&soap);
mas01cr@0 831
mas01cr@0 832 }
mas01cr@0 833
mas01cr@0 834
mas01cr@133 835 void audioDB::status(const char* dbName, adb__statusResponse *adbStatusResponse){
mas01cr@0 836 if(!dbH)
mas01cr@27 837 initTables(dbName, 0, 0);
mas01cr@0 838
mas01cr@0 839 unsigned dudCount=0;
mas01cr@0 840 unsigned nullCount=0;
mas01cr@0 841 for(unsigned k=0; k<dbH->numFiles; k++){
mas01mc@18 842 if(trackTable[k]<sequenceLength){
mas01cr@0 843 dudCount++;
mas01mc@18 844 if(!trackTable[k])
mas01cr@76 845 nullCount++;
mas01cr@0 846 }
mas01cr@0 847 }
mas01cr@76 848
mas01cr@133 849 if(adbStatusResponse == 0) {
mas01cr@76 850
mas01cr@76 851 // Update Header information
mas01cr@76 852 cout << "num files:" << dbH->numFiles << endl;
mas01cr@76 853 cout << "data dim:" << dbH->dim <<endl;
mas01cr@76 854 if(dbH->dim>0){
mas01cr@76 855 cout << "total vectors:" << dbH->length/(sizeof(double)*dbH->dim)<<endl;
mas01cr@108 856 cout << "vectors available:" << (dbH->timesTableOffset-(dbH->dataOffset+dbH->length))/(sizeof(double)*dbH->dim) << endl;
mas01cr@76 857 }
mas01cr@108 858 cout << "total bytes:" << dbH->length << " (" << (100.0*dbH->length)/(dbH->timesTableOffset-dbH->dataOffset) << "%)" << endl;
mas01cr@108 859 cout << "bytes available:" << dbH->timesTableOffset-(dbH->dataOffset+dbH->length) << " (" <<
mas01cr@108 860 (100.0*(dbH->timesTableOffset-(dbH->dataOffset+dbH->length)))/(dbH->timesTableOffset-dbH->dataOffset) << "%)" << endl;
mas01cr@76 861 cout << "flags:" << dbH->flags << endl;
mas01cr@76 862
mas01cr@76 863 cout << "null count: " << nullCount << " small sequence count " << dudCount-nullCount << endl;
mas01cr@76 864 } else {
mas01cr@133 865 adbStatusResponse->result.numFiles = dbH->numFiles;
mas01cr@133 866 adbStatusResponse->result.dim = dbH->dim;
mas01cr@133 867 adbStatusResponse->result.length = dbH->length;
mas01cr@133 868 adbStatusResponse->result.dudCount = dudCount;
mas01cr@133 869 adbStatusResponse->result.nullCount = nullCount;
mas01cr@133 870 adbStatusResponse->result.flags = dbH->flags;
mas01cr@76 871 }
mas01cr@0 872 }
mas01cr@0 873
mas01cr@0 874 void audioDB::dump(const char* dbName){
mas01cr@131 875 if(!dbH) {
mas01cr@27 876 initTables(dbName, 0, 0);
mas01mc@17 877 }
mas01cr@0 878
mas01cr@131 879 if((mkdir(output, S_IRWXU|S_IRWXG|S_IRWXO)) < 0) {
mas01cr@131 880 error("error making output directory", output, "mkdir");
mas01cr@131 881 }
mas01cr@131 882
mas01cr@131 883 char *cwd = new char[PATH_MAX];
mas01cr@131 884
mas01cr@131 885 if ((getcwd(cwd, PATH_MAX)) == 0) {
mas01cr@131 886 error("error getting working directory", "", "getcwd");
mas01cr@131 887 }
mas01cr@131 888
mas01cr@131 889 if((chdir(output)) < 0) {
mas01cr@131 890 error("error changing working directory", output, "chdir");
mas01cr@131 891 }
mas01cr@131 892
mas01cr@131 893 int fLfd, tLfd = 0, kLfd;
mas01cr@131 894 FILE *fLFile, *tLFile = 0, *kLFile;
mas01cr@131 895
mas01cr@131 896 if ((fLfd = open("featureList.txt", O_CREAT|O_RDWR|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) {
mas01cr@131 897 error("error creating featureList file", "featureList.txt", "open");
mas01cr@131 898 }
mas01cr@131 899 int times = dbH->flags & O2_FLAG_TIMES;
mas01cr@131 900 if (times) {
mas01cr@131 901 if ((tLfd = open("timesList.txt", O_CREAT|O_RDWR|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) {
mas01cr@131 902 error("error creating timesList file", "timesList.txt", "open");
mas01cr@131 903 }
mas01cr@131 904 }
mas01cr@131 905 if ((kLfd = open("keyList.txt", O_CREAT|O_RDWR|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) {
mas01cr@131 906 error("error creating keyList file", "keyList.txt", "open");
mas01cr@131 907 }
mas01cr@131 908
mas01cr@131 909 /* can these fail? I sincerely hope not. */
mas01cr@131 910 fLFile = fdopen(fLfd, "w");
mas01cr@131 911 if (times) {
mas01cr@131 912 tLFile = fdopen(tLfd, "w");
mas01cr@131 913 }
mas01cr@131 914 kLFile = fdopen(kLfd, "w");
mas01cr@131 915
mas01cr@131 916 char *fName = new char[256];
mas01cr@131 917 int ffd;
mas01cr@131 918 FILE *tFile;
mas01cr@131 919 unsigned pos = 0;
mas01cr@131 920 for(unsigned k = 0; k < dbH->numFiles; k++) {
mas01cr@131 921 fprintf(kLFile, "%s\n", fileTable + k*O2_FILETABLESIZE);
mas01cr@131 922 snprintf(fName, 256, "%05d.features", k);
mas01cr@131 923 if ((ffd = open(fName, O_CREAT|O_RDWR|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) {
mas01cr@131 924 error("error creating feature file", fName, "open");
mas01cr@131 925 }
mas01cr@131 926 if ((write(ffd, &dbH->dim, sizeof(uint32_t))) < 0) {
mas01cr@131 927 error("error writing dimensions", fName, "write");
mas01cr@131 928 }
mas01cr@131 929
mas01cr@131 930 if ((write(ffd, dataBuf + pos * dbH->dim, trackTable[k] * dbH->dim * sizeof(double))) < 0) {
mas01cr@131 931 error("error writing data", fName, "write");
mas01cr@131 932 }
mas01cr@131 933 fprintf(fLFile, "%s\n", fName);
mas01cr@131 934 close(ffd);
mas01cr@131 935
mas01cr@131 936 if(times) {
mas01cr@131 937 snprintf(fName, 256, "%05d.times", k);
mas01cr@131 938 tFile = fopen(fName, "w");
mas01cr@131 939 for(unsigned i = 0; i < trackTable[k]; i++) {
mas01cr@131 940 // KLUDGE: specifying 16 digits of precision after the decimal
mas01cr@131 941 // point is (but check this!) sufficient to uniquely identify
mas01cr@131 942 // doubles; however, that will cause ugliness, as that's
mas01cr@131 943 // vastly too many for most values of interest. Moving to %a
mas01cr@131 944 // here and scanf() in the timesFile reading might fix this.
mas01cr@131 945 // -- CSR, 2007-10-19
mas01cr@131 946 fprintf(tFile, "%.16e\n", *(timesTable + pos + i));
mas01cr@131 947 }
mas01cr@131 948 fprintf(tLFile, "%s\n", fName);
mas01cr@131 949 }
mas01cr@131 950
mas01cr@131 951 pos += trackTable[k];
mas01cr@131 952 cout << fileTable+k*O2_FILETABLESIZE << " " << trackTable[k] << endl;
mas01cr@131 953 }
mas01cr@131 954
mas01cr@131 955 FILE *scriptFile;
mas01cr@131 956 scriptFile = fopen("restore.sh", "w");
mas01cr@131 957 fprintf(scriptFile, "\
mas01cr@131 958 #! /bin/sh\n\
mas01cr@131 959 #\n\
mas01cr@131 960 # usage: AUDIODB=/path/to/audioDB sh ./restore.sh <newdb>\n\
mas01cr@131 961 \n\
mas01cr@131 962 if [ -z \"${AUDIODB}\" ]; then echo set AUDIODB variable; exit 1; fi\n\
mas01cr@131 963 if [ -z \"$1\" ]; then echo usage: $0 newdb; exit 1; fi\n\n\
mas01cr@131 964 \"${AUDIODB}\" -d \"$1\" -N --size=%d\n", dbH->dbSize / 1000000);
mas01cr@131 965 if(dbH->flags & O2_FLAG_L2NORM) {
mas01cr@131 966 fprintf(scriptFile, "\"${AUDIODB}\" -d \"$1\" -L\n");
mas01cr@131 967 }
mas01cr@131 968 fprintf(scriptFile, "\"${AUDIODB}\" -d \"$1\" -B -F featureList.txt -K keyList.txt");
mas01cr@131 969 if(times) {
mas01cr@131 970 fprintf(scriptFile, " -T timesList.txt");
mas01cr@131 971 }
mas01cr@131 972 fprintf(scriptFile, "\n");
mas01cr@131 973 fclose(scriptFile);
mas01cr@131 974
mas01cr@131 975 if((chdir(cwd)) < 0) {
mas01cr@131 976 error("error changing working directory", cwd, "chdir");
mas01cr@131 977 }
mas01cr@131 978
mas01cr@131 979 fclose(fLFile);
mas01cr@131 980 if(times) {
mas01cr@131 981 fclose(tLFile);
mas01cr@131 982 }
mas01cr@131 983 fclose(kLFile);
mas01cr@131 984 delete[] fName;
mas01cr@131 985
mas01cr@0 986 status(dbName);
mas01cr@0 987 }
mas01cr@0 988
mas01cr@0 989 void audioDB::l2norm(const char* dbName){
mas01cr@50 990 initTables(dbName, true, 0);
mas01cr@0 991 if(dbH->length>0){
mas01cr@0 992 unsigned numVectors = dbH->length/(sizeof(double)*dbH->dim);
mas01cr@0 993 unitNormAndInsertL2(dataBuf, dbH->dim, numVectors, 0); // No append
mas01cr@0 994 }
mas01cr@0 995 // Update database flags
mas01cr@0 996 dbH->flags = dbH->flags|O2_FLAG_L2NORM;
mas01cr@0 997 memcpy (db, dbH, O2_HEADERSIZE);
mas01cr@0 998 }
mas01cr@0 999
mas01cr@0 1000
mas01cr@0 1001
mas01cr@133 1002 void audioDB::query(const char* dbName, const char* inFile, adb__queryResponse *adbQueryResponse){
mas01cr@0 1003 switch(queryType){
mas01cr@105 1004 case O2_POINT_QUERY:
mas01cr@133 1005 pointQuery(dbName, inFile, adbQueryResponse);
mas01cr@0 1006 break;
mas01cr@105 1007 case O2_SEQUENCE_QUERY:
mas01mc@17 1008 if(radius==0)
mas01cr@133 1009 trackSequenceQueryNN(dbName, inFile, adbQueryResponse);
mas01mc@17 1010 else
mas01cr@133 1011 trackSequenceQueryRad(dbName, inFile, adbQueryResponse);
mas01cr@0 1012 break;
mas01cr@105 1013 case O2_TRACK_QUERY:
mas01cr@133 1014 trackPointQuery(dbName, inFile, adbQueryResponse);
mas01cr@0 1015 break;
mas01cr@0 1016 default:
mas01cr@0 1017 error("unrecognized queryType in query()");
mas01cr@0 1018
mas01cr@0 1019 }
mas01cr@0 1020 }
mas01cr@0 1021
mas01cr@0 1022 //return ordinal position of key in keyTable
mas01cr@0 1023 unsigned audioDB::getKeyPos(char* key){
mas01cr@0 1024 for(unsigned k=0; k<dbH->numFiles; k++)
mas01cr@0 1025 if(strncmp(fileTable + k*O2_FILETABLESIZE, key, strlen(key))==0)
mas01cr@0 1026 return k;
mas01cr@0 1027 error("Key not found",key);
mas01cr@0 1028 return O2_ERR_KEYNOTFOUND;
mas01cr@0 1029 }
mas01cr@0 1030
mas01cr@0 1031 // Basic point query engine
mas01cr@133 1032 void audioDB::pointQuery(const char* dbName, const char* inFile, adb__queryResponse *adbQueryResponse){
mas01cr@0 1033
mas01cr@27 1034 initTables(dbName, 0, inFile);
mas01cr@0 1035
mas01cr@0 1036 // For each input vector, find the closest pointNN matching output vectors and report
mas01cr@0 1037 // we use stdout in this stub version
mas01cr@0 1038 unsigned numVectors = (statbuf.st_size-sizeof(int))/(sizeof(double)*dbH->dim);
mas01cr@0 1039
mas01cr@0 1040 double* query = (double*)(indata+sizeof(int));
mas01cr@0 1041 double* data = dataBuf;
mas01cr@0 1042 double* queryCopy = 0;
mas01cr@0 1043
mas01cr@0 1044 if( dbH->flags & O2_FLAG_L2NORM ){
mas01cr@0 1045 // Make a copy of the query
mas01cr@0 1046 queryCopy = new double[numVectors*dbH->dim];
mas01cr@0 1047 qNorm = new double[numVectors];
mas01cr@0 1048 assert(queryCopy&&qNorm);
mas01cr@0 1049 memcpy(queryCopy, query, numVectors*dbH->dim*sizeof(double));
mas01cr@0 1050 unitNorm(queryCopy, dbH->dim, numVectors, qNorm);
mas01cr@0 1051 query = queryCopy;
mas01cr@0 1052 }
mas01cr@0 1053
mas01cr@0 1054 // Make temporary dynamic memory for results
mas01cr@0 1055 assert(pointNN>0 && pointNN<=O2_MAXNN);
mas01cr@0 1056 double distances[pointNN];
mas01cr@0 1057 unsigned qIndexes[pointNN];
mas01cr@0 1058 unsigned sIndexes[pointNN];
mas01cr@0 1059 for(unsigned k=0; k<pointNN; k++){
mas01cr@62 1060 distances[k]=-DBL_MAX;
mas01cr@0 1061 qIndexes[k]=~0;
mas01cr@0 1062 sIndexes[k]=~0;
mas01cr@0 1063 }
mas01cr@0 1064
mas01cr@0 1065 unsigned j=numVectors;
mas01cr@0 1066 unsigned k,l,n;
mas01cr@0 1067 double thisDist;
mas01cr@0 1068
mas01cr@0 1069 unsigned totalVecs=dbH->length/(dbH->dim*sizeof(double));
mas01cr@0 1070 double meanQdur = 0;
mas01cr@0 1071 double* timesdata = 0;
mas01cr@0 1072 double* dbdurs = 0;
mas01cr@0 1073
mas01cr@0 1074 if(usingTimes && !(dbH->flags & O2_FLAG_TIMES)){
mas01cr@0 1075 cerr << "warning: ignoring query timestamps for non-timestamped database" << endl;
mas01cr@0 1076 usingTimes=0;
mas01cr@0 1077 }
mas01cr@0 1078
mas01cr@0 1079 else if(!usingTimes && (dbH->flags & O2_FLAG_TIMES))
mas01cr@0 1080 cerr << "warning: no timestamps given for query. Ignoring database timestamps." << endl;
mas01cr@0 1081
mas01cr@0 1082 else if(usingTimes && (dbH->flags & O2_FLAG_TIMES)){
mas01cr@0 1083 timesdata = new double[numVectors];
mas01cr@0 1084 insertTimeStamps(numVectors, timesFile, timesdata);
mas01cr@0 1085 // Calculate durations of points
mas01cr@0 1086 for(k=0; k<numVectors-1; k++){
mas01cr@0 1087 timesdata[k]=timesdata[k+1]-timesdata[k];
mas01cr@0 1088 meanQdur+=timesdata[k];
mas01cr@0 1089 }
mas01cr@0 1090 meanQdur/=k;
mas01cr@0 1091 // Individual exhaustive timepoint durations
mas01cr@0 1092 dbdurs = new double[totalVecs];
mas01cr@0 1093 for(k=0; k<totalVecs-1; k++)
mas01cr@0 1094 dbdurs[k]=timesTable[k+1]-timesTable[k];
mas01cr@0 1095 j--; // decrement vector counter by one
mas01cr@0 1096 }
mas01cr@0 1097
mas01cr@0 1098 if(usingQueryPoint)
mas01cr@0 1099 if(queryPoint>numVectors-1)
mas01cr@0 1100 error("queryPoint > numVectors in query");
mas01cr@0 1101 else{
mas01cr@60 1102 if(verbosity>1) {
mas01cr@0 1103 cerr << "query point: " << queryPoint << endl; cerr.flush();
mas01cr@60 1104 }
mas01cr@0 1105 query=query+queryPoint*dbH->dim;
mas01cr@0 1106 numVectors=queryPoint+1;
mas01cr@0 1107 j=1;
mas01cr@0 1108 }
mas01cr@0 1109
mas01cr@0 1110 gettimeofday(&tv1, NULL);
mas01cr@0 1111 while(j--){ // query
mas01cr@0 1112 data=dataBuf;
mas01cr@0 1113 k=totalVecs; // number of database vectors
mas01cr@0 1114 while(k--){ // database
mas01cr@0 1115 thisDist=0;
mas01cr@0 1116 l=dbH->dim;
mas01cr@0 1117 double* q=query;
mas01cr@0 1118 while(l--)
mas01cr@0 1119 thisDist+=*q++**data++;
mas01cr@0 1120 if(!usingTimes ||
mas01cr@0 1121 (usingTimes
mas01cr@0 1122 && fabs(dbdurs[totalVecs-k-1]-timesdata[numVectors-j-1])<timesdata[numVectors-j-1]*timesTol)){
mas01cr@0 1123 n=pointNN;
mas01cr@0 1124 while(n--){
mas01cr@0 1125 if(thisDist>=distances[n]){
mas01cr@0 1126 if((n==0 || thisDist<=distances[n-1])){
mas01cr@0 1127 // Copy all values above up the queue
mas01cr@0 1128 for( l=pointNN-1 ; l >= n+1 ; l--){
mas01cr@0 1129 distances[l]=distances[l-1];
mas01cr@0 1130 qIndexes[l]=qIndexes[l-1];
mas01cr@0 1131 sIndexes[l]=sIndexes[l-1];
mas01cr@0 1132 }
mas01cr@0 1133 distances[n]=thisDist;
mas01cr@0 1134 qIndexes[n]=numVectors-j-1;
mas01cr@0 1135 sIndexes[n]=dbH->length/(sizeof(double)*dbH->dim)-k-1;
mas01cr@0 1136 break;
mas01cr@0 1137 }
mas01cr@0 1138 }
mas01cr@0 1139 else
mas01cr@0 1140 break;
mas01cr@0 1141 }
mas01cr@0 1142 }
mas01cr@0 1143 }
mas01cr@0 1144 // Move query pointer to next query point
mas01cr@0 1145 query+=dbH->dim;
mas01cr@0 1146 }
mas01cr@0 1147
mas01cr@0 1148 gettimeofday(&tv2, NULL);
mas01cr@60 1149 if(verbosity>1) {
mas01cr@0 1150 cerr << endl << " elapsed time:" << ( tv2.tv_sec*1000 + tv2.tv_usec/1000 ) - ( tv1.tv_sec*1000+tv1.tv_usec/1000 ) << " msec" << endl;
mas01cr@60 1151 }
mas01cr@0 1152
mas01cr@133 1153 if(adbQueryResponse==0){
mas01cr@0 1154 // Output answer
mas01cr@0 1155 // Loop over nearest neighbours
mas01cr@0 1156 for(k=0; k < pointNN; k++){
mas01cr@0 1157 // Scan for key
mas01mc@18 1158 unsigned cumTrack=0;
mas01cr@0 1159 for(l=0 ; l<dbH->numFiles; l++){
mas01mc@18 1160 cumTrack+=trackTable[l];
mas01mc@18 1161 if(sIndexes[k]<cumTrack){
mas01cr@0 1162 cout << fileTable+l*O2_FILETABLESIZE << " " << distances[k] << " " << qIndexes[k] << " "
mas01mc@18 1163 << sIndexes[k]+trackTable[l]-cumTrack << endl;
mas01cr@0 1164 break;
mas01cr@0 1165 }
mas01cr@0 1166 }
mas01cr@0 1167 }
mas01cr@0 1168 }
mas01cr@0 1169 else{ // Process Web Services Query
mas01cr@89 1170 int listLen;
mas01cr@89 1171 for(k = 0; k < pointNN; k++) {
mas01cr@89 1172 if(distances[k] == -DBL_MAX)
mas01cr@89 1173 break;
mas01cr@89 1174 }
mas01cr@89 1175 listLen = k;
mas01cr@89 1176
mas01cr@133 1177 adbQueryResponse->result.__sizeRlist=listLen;
mas01cr@133 1178 adbQueryResponse->result.__sizeDist=listLen;
mas01cr@133 1179 adbQueryResponse->result.__sizeQpos=listLen;
mas01cr@133 1180 adbQueryResponse->result.__sizeSpos=listLen;
mas01cr@133 1181 adbQueryResponse->result.Rlist= new char*[listLen];
mas01cr@133 1182 adbQueryResponse->result.Dist = new double[listLen];
mas01cr@133 1183 adbQueryResponse->result.Qpos = new unsigned int[listLen];
mas01cr@133 1184 adbQueryResponse->result.Spos = new unsigned int[listLen];
mas01cr@133 1185 for(k=0; k<(unsigned)adbQueryResponse->result.__sizeRlist; k++){
mas01cr@133 1186 adbQueryResponse->result.Rlist[k]=new char[O2_MAXFILESTR];
mas01cr@133 1187 adbQueryResponse->result.Dist[k]=distances[k];
mas01cr@133 1188 adbQueryResponse->result.Qpos[k]=qIndexes[k];
mas01mc@18 1189 unsigned cumTrack=0;
mas01cr@0 1190 for(l=0 ; l<dbH->numFiles; l++){
mas01mc@18 1191 cumTrack+=trackTable[l];
mas01mc@18 1192 if(sIndexes[k]<cumTrack){
mas01cr@133 1193 sprintf(adbQueryResponse->result.Rlist[k], "%s", fileTable+l*O2_FILETABLESIZE);
mas01cr@0 1194 break;
mas01cr@0 1195 }
mas01cr@0 1196 }
mas01cr@133 1197 adbQueryResponse->result.Spos[k]=sIndexes[k]+trackTable[l]-cumTrack;
mas01cr@0 1198 }
mas01cr@0 1199 }
mas01cr@0 1200
mas01cr@0 1201 // Clean up
mas01cr@0 1202 if(queryCopy)
mas01cr@0 1203 delete queryCopy;
mas01cr@0 1204 if(qNorm)
mas01cr@0 1205 delete qNorm;
mas01cr@0 1206 if(timesdata)
mas01cr@0 1207 delete timesdata;
mas01cr@0 1208 if(dbdurs)
mas01cr@0 1209 delete dbdurs;
mas01cr@0 1210 }
mas01cr@0 1211
mas01mc@18 1212 // trackPointQuery
mas01mc@18 1213 // return the trackNN closest tracks to the query track
mas01mc@18 1214 // uses average of pointNN points per track
mas01cr@133 1215 void audioDB::trackPointQuery(const char* dbName, const char* inFile, adb__queryResponse *adbQueryResponse){
mas01cr@27 1216 initTables(dbName, 0, inFile);
mas01cr@0 1217
mas01cr@0 1218 // For each input vector, find the closest pointNN matching output vectors and report
mas01cr@0 1219 unsigned numVectors = (statbuf.st_size-sizeof(int))/(sizeof(double)*dbH->dim);
mas01cr@0 1220 double* query = (double*)(indata+sizeof(int));
mas01cr@0 1221 double* data = dataBuf;
mas01cr@0 1222 double* queryCopy = 0;
mas01cr@0 1223
mas01cr@0 1224 if( dbH->flags & O2_FLAG_L2NORM ){
mas01cr@0 1225 // Make a copy of the query
mas01cr@0 1226 queryCopy = new double[numVectors*dbH->dim];
mas01cr@0 1227 qNorm = new double[numVectors];
mas01cr@0 1228 assert(queryCopy&&qNorm);
mas01cr@0 1229 memcpy(queryCopy, query, numVectors*dbH->dim*sizeof(double));
mas01cr@0 1230 unitNorm(queryCopy, dbH->dim, numVectors, qNorm);
mas01cr@0 1231 query = queryCopy;
mas01cr@0 1232 }
mas01cr@0 1233
mas01cr@0 1234 assert(pointNN>0 && pointNN<=O2_MAXNN);
mas01mc@18 1235 assert(trackNN>0 && trackNN<=O2_MAXNN);
mas01cr@0 1236
mas01cr@0 1237 // Make temporary dynamic memory for results
mas01mc@18 1238 double trackDistances[trackNN];
mas01mc@18 1239 unsigned trackIDs[trackNN];
mas01mc@18 1240 unsigned trackQIndexes[trackNN];
mas01mc@18 1241 unsigned trackSIndexes[trackNN];
mas01cr@0 1242
mas01cr@0 1243 double distances[pointNN];
mas01cr@0 1244 unsigned qIndexes[pointNN];
mas01cr@0 1245 unsigned sIndexes[pointNN];
mas01cr@0 1246
mas01cr@0 1247 unsigned j=numVectors; // number of query points
mas01mc@18 1248 unsigned k,l,n, track, trackOffset=0, processedTracks=0;
mas01cr@0 1249 double thisDist;
mas01cr@0 1250
mas01cr@0 1251 for(k=0; k<pointNN; k++){
mas01cr@66 1252 distances[k]=-DBL_MAX;
mas01cr@0 1253 qIndexes[k]=~0;
mas01cr@0 1254 sIndexes[k]=~0;
mas01cr@0 1255 }
mas01cr@0 1256
mas01mc@18 1257 for(k=0; k<trackNN; k++){
mas01cr@66 1258 trackDistances[k]=-DBL_MAX;
mas01mc@18 1259 trackQIndexes[k]=~0;
mas01mc@18 1260 trackSIndexes[k]=~0;
mas01mc@18 1261 trackIDs[k]=~0;
mas01cr@0 1262 }
mas01cr@0 1263
mas01cr@0 1264 double meanQdur = 0;
mas01cr@0 1265 double* timesdata = 0;
mas01cr@0 1266 double* meanDBdur = 0;
mas01cr@0 1267
mas01cr@0 1268 if(usingTimes && !(dbH->flags & O2_FLAG_TIMES)){
mas01cr@0 1269 cerr << "warning: ignoring query timestamps for non-timestamped database" << endl;
mas01cr@0 1270 usingTimes=0;
mas01cr@0 1271 }
mas01cr@0 1272
mas01cr@0 1273 else if(!usingTimes && (dbH->flags & O2_FLAG_TIMES))
mas01cr@0 1274 cerr << "warning: no timestamps given for query. Ignoring database timestamps." << endl;
mas01cr@0 1275
mas01cr@0 1276 else if(usingTimes && (dbH->flags & O2_FLAG_TIMES)){
mas01cr@0 1277 timesdata = new double[numVectors];
mas01cr@0 1278 insertTimeStamps(numVectors, timesFile, timesdata);
mas01cr@0 1279 // Calculate durations of points
mas01cr@0 1280 for(k=0; k<numVectors-1; k++){
mas01cr@0 1281 timesdata[k]=timesdata[k+1]-timesdata[k];
mas01cr@0 1282 meanQdur+=timesdata[k];
mas01cr@0 1283 }
mas01cr@0 1284 meanQdur/=k;
mas01cr@0 1285 meanDBdur = new double[dbH->numFiles];
mas01cr@0 1286 for(k=0; k<dbH->numFiles; k++){
mas01cr@0 1287 meanDBdur[k]=0.0;
mas01mc@18 1288 for(j=0; j<trackTable[k]-1 ; j++)
mas01cr@0 1289 meanDBdur[k]+=timesTable[j+1]-timesTable[j];
mas01cr@0 1290 meanDBdur[k]/=j;
mas01cr@0 1291 }
mas01cr@0 1292 }
mas01cr@0 1293
mas01cr@0 1294 if(usingQueryPoint)
mas01cr@0 1295 if(queryPoint>numVectors-1)
mas01cr@0 1296 error("queryPoint > numVectors in query");
mas01cr@0 1297 else{
mas01cr@60 1298 if(verbosity>1) {
mas01cr@0 1299 cerr << "query point: " << queryPoint << endl; cerr.flush();
mas01cr@60 1300 }
mas01cr@0 1301 query=query+queryPoint*dbH->dim;
mas01cr@0 1302 numVectors=queryPoint+1;
mas01cr@0 1303 }
mas01cr@0 1304
mas01mc@18 1305 // build track offset table
mas01mc@18 1306 unsigned *trackOffsetTable = new unsigned[dbH->numFiles];
mas01mc@18 1307 unsigned cumTrack=0;
mas01mc@18 1308 unsigned trackIndexOffset;
mas01cr@0 1309 for(k=0; k<dbH->numFiles;k++){
mas01mc@18 1310 trackOffsetTable[k]=cumTrack;
mas01mc@18 1311 cumTrack+=trackTable[k]*dbH->dim;
mas01cr@0 1312 }
mas01cr@0 1313
mas01cr@0 1314 char nextKey[MAXSTR];
mas01cr@0 1315
mas01cr@0 1316 gettimeofday(&tv1, NULL);
mas01cr@0 1317
mas01mc@18 1318 for(processedTracks=0, track=0 ; processedTracks < dbH->numFiles ; track++, processedTracks++){
mas01mc@18 1319 if(trackFile){
mas01mc@18 1320 if(!trackFile->eof()){
mas01mc@18 1321 trackFile->getline(nextKey,MAXSTR);
mas01mc@18 1322 track=getKeyPos(nextKey);
mas01cr@0 1323 }
mas01cr@0 1324 else
mas01cr@0 1325 break;
mas01cr@0 1326 }
mas01mc@18 1327 trackOffset=trackOffsetTable[track]; // numDoubles offset
mas01mc@18 1328 trackIndexOffset=trackOffset/dbH->dim; // numVectors offset
mas01cr@60 1329 if(verbosity>7) {
mas01mc@18 1330 cerr << track << "." << trackOffset/(dbH->dim) << "." << trackTable[track] << " | ";cerr.flush();
mas01cr@60 1331 }
mas01cr@0 1332
mas01cr@0 1333 if(dbH->flags & O2_FLAG_L2NORM)
mas01cr@0 1334 usingQueryPoint?query=queryCopy+queryPoint*dbH->dim:query=queryCopy;
mas01cr@0 1335 else
mas01cr@0 1336 usingQueryPoint?query=(double*)(indata+sizeof(int))+queryPoint*dbH->dim:query=(double*)(indata+sizeof(int));
mas01cr@0 1337 if(usingQueryPoint)
mas01cr@0 1338 j=1;
mas01cr@0 1339 else
mas01cr@0 1340 j=numVectors;
mas01cr@0 1341 while(j--){
mas01mc@18 1342 k=trackTable[track]; // number of vectors in track
mas01mc@18 1343 data=dataBuf+trackOffset; // data for track
mas01cr@0 1344 while(k--){
mas01cr@0 1345 thisDist=0;
mas01cr@0 1346 l=dbH->dim;
mas01cr@0 1347 double* q=query;
mas01cr@0 1348 while(l--)
mas01cr@0 1349 thisDist+=*q++**data++;
mas01cr@0 1350 if(!usingTimes ||
mas01cr@0 1351 (usingTimes
mas01mc@18 1352 && fabs(meanDBdur[track]-meanQdur)<meanQdur*timesTol)){
mas01cr@0 1353 n=pointNN;
mas01cr@0 1354 while(n--){
mas01cr@0 1355 if(thisDist>=distances[n]){
mas01cr@0 1356 if((n==0 || thisDist<=distances[n-1])){
mas01cr@0 1357 // Copy all values above up the queue
mas01cr@0 1358 for( l=pointNN-1 ; l > n ; l--){
mas01cr@0 1359 distances[l]=distances[l-1];
mas01cr@0 1360 qIndexes[l]=qIndexes[l-1];
mas01cr@0 1361 sIndexes[l]=sIndexes[l-1];
mas01cr@0 1362 }
mas01cr@0 1363 distances[n]=thisDist;
mas01cr@0 1364 qIndexes[n]=numVectors-j-1;
mas01mc@18 1365 sIndexes[n]=trackTable[track]-k-1;
mas01cr@0 1366 break;
mas01cr@0 1367 }
mas01cr@0 1368 }
mas01cr@0 1369 else
mas01cr@0 1370 break;
mas01cr@0 1371 }
mas01cr@0 1372 }
mas01mc@18 1373 } // track
mas01cr@0 1374 // Move query pointer to next query point
mas01cr@0 1375 query+=dbH->dim;
mas01cr@0 1376 } // query
mas01mc@18 1377 // Take the average of this track's distance
mas01mc@18 1378 // Test the track distances
mas01cr@0 1379 thisDist=0;
mas01cr@66 1380 for (n = 0; n < pointNN; n++) {
mas01cr@66 1381 if (distances[n] == -DBL_MAX) break;
mas01cr@66 1382 thisDist += distances[n];
mas01cr@66 1383 }
mas01cr@66 1384 thisDist /= n;
mas01cr@66 1385
mas01mc@18 1386 n=trackNN;
mas01cr@0 1387 while(n--){
mas01mc@18 1388 if(thisDist>=trackDistances[n]){
mas01mc@18 1389 if((n==0 || thisDist<=trackDistances[n-1])){
mas01cr@0 1390 // Copy all values above up the queue
mas01cr@74 1391 for( l=trackNN-1 ; l > n ; l--){
mas01mc@18 1392 trackDistances[l]=trackDistances[l-1];
mas01mc@18 1393 trackQIndexes[l]=trackQIndexes[l-1];
mas01mc@18 1394 trackSIndexes[l]=trackSIndexes[l-1];
mas01mc@18 1395 trackIDs[l]=trackIDs[l-1];
mas01cr@0 1396 }
mas01mc@18 1397 trackDistances[n]=thisDist;
mas01mc@18 1398 trackQIndexes[n]=qIndexes[0];
mas01mc@18 1399 trackSIndexes[n]=sIndexes[0];
mas01mc@18 1400 trackIDs[n]=track;
mas01cr@0 1401 break;
mas01cr@0 1402 }
mas01cr@0 1403 }
mas01cr@0 1404 else
mas01cr@0 1405 break;
mas01cr@0 1406 }
mas01cr@0 1407 for(unsigned k=0; k<pointNN; k++){
mas01cr@66 1408 distances[k]=-DBL_MAX;
mas01cr@0 1409 qIndexes[k]=~0;
mas01cr@0 1410 sIndexes[k]=~0;
mas01cr@0 1411 }
mas01mc@18 1412 } // tracks
mas01cr@0 1413 gettimeofday(&tv2, NULL);
mas01cr@0 1414
mas01cr@60 1415 if(verbosity>1) {
mas01mc@18 1416 cerr << endl << "processed tracks :" << processedTracks
mas01cr@0 1417 << " elapsed time:" << ( tv2.tv_sec*1000 + tv2.tv_usec/1000 ) - ( tv1.tv_sec*1000+tv1.tv_usec/1000 ) << " msec" << endl;
mas01cr@60 1418 }
mas01cr@0 1419
mas01cr@133 1420 if(adbQueryResponse==0){
mas01cr@60 1421 if(verbosity>1) {
mas01cr@0 1422 cerr<<endl;
mas01cr@60 1423 }
mas01cr@0 1424 // Output answer
mas01cr@0 1425 // Loop over nearest neighbours
mas01mc@18 1426 for(k=0; k < min(trackNN,processedTracks); k++)
mas01mc@18 1427 cout << fileTable+trackIDs[k]*O2_FILETABLESIZE
mas01mc@18 1428 << " " << trackDistances[k] << " " << trackQIndexes[k] << " " << trackSIndexes[k] << endl;
mas01cr@0 1429 }
mas01cr@0 1430 else{ // Process Web Services Query
mas01mc@18 1431 int listLen = min(trackNN, processedTracks);
mas01cr@133 1432 adbQueryResponse->result.__sizeRlist=listLen;
mas01cr@133 1433 adbQueryResponse->result.__sizeDist=listLen;
mas01cr@133 1434 adbQueryResponse->result.__sizeQpos=listLen;
mas01cr@133 1435 adbQueryResponse->result.__sizeSpos=listLen;
mas01cr@133 1436 adbQueryResponse->result.Rlist= new char*[listLen];
mas01cr@133 1437 adbQueryResponse->result.Dist = new double[listLen];
mas01cr@133 1438 adbQueryResponse->result.Qpos = new unsigned int[listLen];
mas01cr@133 1439 adbQueryResponse->result.Spos = new unsigned int[listLen];
mas01cr@133 1440 for(k=0; k<(unsigned)adbQueryResponse->result.__sizeRlist; k++){
mas01cr@133 1441 adbQueryResponse->result.Rlist[k]=new char[O2_MAXFILESTR];
mas01cr@133 1442 adbQueryResponse->result.Dist[k]=trackDistances[k];
mas01cr@133 1443 adbQueryResponse->result.Qpos[k]=trackQIndexes[k];
mas01cr@133 1444 adbQueryResponse->result.Spos[k]=trackSIndexes[k];
mas01cr@133 1445 sprintf(adbQueryResponse->result.Rlist[k], "%s", fileTable+trackIDs[k]*O2_FILETABLESIZE);
mas01cr@0 1446 }
mas01cr@0 1447 }
mas01cr@0 1448
mas01cr@0 1449
mas01cr@0 1450 // Clean up
mas01mc@18 1451 if(trackOffsetTable)
mas01mc@18 1452 delete trackOffsetTable;
mas01cr@0 1453 if(queryCopy)
mas01cr@0 1454 delete queryCopy;
mas01cr@0 1455 if(qNorm)
mas01cr@0 1456 delete qNorm;
mas01cr@0 1457 if(timesdata)
mas01cr@0 1458 delete timesdata;
mas01cr@0 1459 if(meanDBdur)
mas01cr@0 1460 delete meanDBdur;
mas01cr@0 1461
mas01cr@0 1462 }
mas01cr@0 1463
mas01cr@0 1464
mas01mc@20 1465 // k nearest-neighbor (k-NN) search between query and target tracks
mas01mc@20 1466 // efficient implementation based on matched filter
mas01mc@20 1467 // assumes normed shingles
mas01mc@20 1468 // outputs distances of retrieved shingles, max retreived = pointNN shingles per per track
mas01cr@133 1469 void audioDB::trackSequenceQueryNN(const char* dbName, const char* inFile, adb__queryResponse *adbQueryResponse){
mas01cr@0 1470
mas01cr@27 1471 initTables(dbName, 0, inFile);
mas01cr@0 1472
mas01cr@0 1473 // For each input vector, find the closest pointNN matching output vectors and report
mas01cr@0 1474 // we use stdout in this stub version
mas01cr@0 1475 unsigned numVectors = (statbuf.st_size-sizeof(int))/(sizeof(double)*dbH->dim);
mas01cr@0 1476 double* query = (double*)(indata+sizeof(int));
mas01cr@0 1477 double* queryCopy = 0;
mas01cr@0 1478
mas01cr@0 1479 double qMeanL2;
mas01cr@0 1480 double* sMeanL2;
mas01cr@0 1481
mas01cr@0 1482 unsigned USE_THRESH=0;
mas01cr@0 1483 double SILENCE_THRESH=0;
mas01cr@0 1484 double DIFF_THRESH=0;
mas01cr@0 1485
mas01cr@0 1486 if(!(dbH->flags & O2_FLAG_L2NORM) )
mas01cr@55 1487 error("Database must be L2 normed for sequence query","use -L2NORM");
mas01cr@55 1488
mas01cr@55 1489 if(numVectors<sequenceLength)
mas01cr@55 1490 error("Query shorter than requested sequence length", "maybe use -l");
mas01cr@0 1491
mas01cr@60 1492 if(verbosity>1) {
mas01cr@0 1493 cerr << "performing norms ... "; cerr.flush();
mas01cr@60 1494 }
mas01cr@0 1495 unsigned dbVectors = dbH->length/(sizeof(double)*dbH->dim);
mas01mc@20 1496
mas01cr@0 1497 // Make a copy of the query
mas01cr@0 1498 queryCopy = new double[numVectors*dbH->dim];
mas01cr@0 1499 memcpy(queryCopy, query, numVectors*dbH->dim*sizeof(double));
mas01cr@0 1500 qNorm = new double[numVectors];
mas01cr@0 1501 sNorm = new double[dbVectors];
mas01cr@0 1502 sMeanL2=new double[dbH->numFiles];
mas01cr@0 1503 assert(qNorm&&sNorm&&queryCopy&&sMeanL2&&sequenceLength);
mas01cr@0 1504 unitNorm(queryCopy, dbH->dim, numVectors, qNorm);
mas01cr@0 1505 query = queryCopy;
mas01mc@20 1506
mas01cr@0 1507 // Make norm measurements relative to sequenceLength
mas01cr@0 1508 unsigned w = sequenceLength-1;
mas01cr@0 1509 unsigned i,j;
mas01cr@0 1510 double* ps;
mas01cr@0 1511 double tmp1,tmp2;
mas01mc@20 1512
mas01cr@0 1513 // Copy the L2 norm values to core to avoid disk random access later on
mas01cr@0 1514 memcpy(sNorm, l2normTable, dbVectors*sizeof(double));
mas01cr@125 1515 double* qnPtr = qNorm;
mas01cr@0 1516 double* snPtr = sNorm;
mas01cr@0 1517 for(i=0; i<dbH->numFiles; i++){
mas01mc@20 1518 if(trackTable[i]>=sequenceLength){
mas01cr@0 1519 tmp1=*snPtr;
mas01cr@0 1520 j=1;
mas01cr@0 1521 w=sequenceLength-1;
mas01cr@0 1522 while(w--)
mas01cr@0 1523 *snPtr+=snPtr[j++];
mas01cr@0 1524 ps = snPtr+1;
mas01mc@18 1525 w=trackTable[i]-sequenceLength; // +1 - 1
mas01cr@0 1526 while(w--){
mas01cr@0 1527 tmp2=*ps;
mas01mc@20 1528 *ps=*(ps-1)-tmp1+*(ps+sequenceLength-1);
mas01cr@0 1529 tmp1=tmp2;
mas01cr@0 1530 ps++;
mas01cr@0 1531 }
mas01mc@20 1532 ps = snPtr;
mas01mc@20 1533 w=trackTable[i]-sequenceLength+1;
mas01mc@20 1534 while(w--){
mas01mc@20 1535 *ps=sqrt(*ps);
mas01mc@20 1536 ps++;
mas01mc@20 1537 }
mas01cr@0 1538 }
mas01mc@18 1539 snPtr+=trackTable[i];
mas01cr@0 1540 }
mas01cr@0 1541
mas01cr@0 1542 double* pn = sMeanL2;
mas01cr@0 1543 w=dbH->numFiles;
mas01cr@0 1544 while(w--)
mas01cr@0 1545 *pn++=0.0;
mas01cr@0 1546 ps=sNorm;
mas01mc@18 1547 unsigned processedTracks=0;
mas01cr@0 1548 for(i=0; i<dbH->numFiles; i++){
mas01mc@18 1549 if(trackTable[i]>sequenceLength-1){
mas01cr@57 1550 w = trackTable[i]-sequenceLength+1;
mas01cr@0 1551 pn = sMeanL2+i;
mas01mc@20 1552 *pn=0;
mas01cr@0 1553 while(w--)
mas01mc@20 1554 if(*ps>0)
mas01mc@20 1555 *pn+=*ps++;
mas01cr@57 1556 *pn/=trackTable[i]-sequenceLength+1;
mas01cr@0 1557 SILENCE_THRESH+=*pn;
mas01mc@18 1558 processedTracks++;
mas01cr@0 1559 }
mas01mc@18 1560 ps = sNorm + trackTable[i];
mas01cr@0 1561 }
mas01cr@60 1562 if(verbosity>1) {
mas01mc@18 1563 cerr << "processedTracks: " << processedTracks << endl;
mas01cr@60 1564 }
mas01mc@20 1565
mas01mc@18 1566 SILENCE_THRESH/=processedTracks;
mas01cr@0 1567 USE_THRESH=1; // Turn thresholding on
mas01mc@20 1568 DIFF_THRESH=SILENCE_THRESH; // mean shingle power
mas01mc@20 1569 SILENCE_THRESH/=5; // 20% of the mean shingle power is SILENCE
mas01cr@60 1570 if(verbosity>4) {
mas01mc@20 1571 cerr << "silence thresh: " << SILENCE_THRESH;
mas01cr@60 1572 }
mas01cr@0 1573 w=sequenceLength-1;
mas01cr@0 1574 i=1;
mas01cr@125 1575 tmp1=*qnPtr;
mas01cr@0 1576 while(w--)
mas01cr@125 1577 *qnPtr+=qnPtr[i++];
mas01cr@125 1578 ps = qnPtr+1;
mas01mc@20 1579 w=numVectors-sequenceLength; // +1 -1
mas01cr@0 1580 while(w--){
mas01cr@0 1581 tmp2=*ps;
mas01mc@20 1582 *ps=*(ps-1)-tmp1+*(ps+sequenceLength-1);
mas01cr@0 1583 tmp1=tmp2;
mas01mc@20 1584 ps++;
mas01mc@20 1585 }
mas01cr@125 1586 ps = qnPtr;
mas01mc@20 1587 qMeanL2 = 0;
mas01mc@20 1588 w=numVectors-sequenceLength+1;
mas01mc@20 1589 while(w--){
mas01mc@20 1590 *ps=sqrt(*ps);
mas01mc@20 1591 qMeanL2+=*ps++;
mas01cr@0 1592 }
mas01cr@0 1593 qMeanL2 /= numVectors-sequenceLength+1;
mas01mc@20 1594
mas01cr@60 1595 if(verbosity>1) {
mas01cr@60 1596 cerr << "done." << endl;
mas01cr@60 1597 }
mas01cr@0 1598
mas01cr@60 1599 if(verbosity>1) {
mas01mc@18 1600 cerr << "matching tracks..." << endl;
mas01cr@60 1601 }
mas01cr@0 1602
mas01cr@0 1603 assert(pointNN>0 && pointNN<=O2_MAXNN);
mas01mc@18 1604 assert(trackNN>0 && trackNN<=O2_MAXNN);
mas01cr@0 1605
mas01cr@0 1606 // Make temporary dynamic memory for results
mas01mc@18 1607 double trackDistances[trackNN];
mas01mc@18 1608 unsigned trackIDs[trackNN];
mas01mc@18 1609 unsigned trackQIndexes[trackNN];
mas01mc@18 1610 unsigned trackSIndexes[trackNN];
mas01cr@0 1611
mas01cr@0 1612 double distances[pointNN];
mas01cr@0 1613 unsigned qIndexes[pointNN];
mas01cr@0 1614 unsigned sIndexes[pointNN];
mas01cr@0 1615
mas01cr@0 1616
mas01mc@18 1617 unsigned k,l,m,n,track,trackOffset=0, HOP_SIZE=sequenceHop, wL=sequenceLength;
mas01cr@0 1618 double thisDist;
mas01cr@0 1619
mas01cr@0 1620 for(k=0; k<pointNN; k++){
mas01mc@20 1621 distances[k]=1.0e6;
mas01cr@0 1622 qIndexes[k]=~0;
mas01cr@0 1623 sIndexes[k]=~0;
mas01cr@0 1624 }
mas01cr@0 1625
mas01mc@18 1626 for(k=0; k<trackNN; k++){
mas01mc@20 1627 trackDistances[k]=1.0e6;
mas01mc@18 1628 trackQIndexes[k]=~0;
mas01mc@18 1629 trackSIndexes[k]=~0;
mas01mc@18 1630 trackIDs[k]=~0;
mas01cr@0 1631 }
mas01cr@0 1632
mas01cr@0 1633 // Timestamp and durations processing
mas01cr@0 1634 double meanQdur = 0;
mas01cr@0 1635 double* timesdata = 0;
mas01cr@0 1636 double* meanDBdur = 0;
mas01cr@0 1637
mas01cr@0 1638 if(usingTimes && !(dbH->flags & O2_FLAG_TIMES)){
mas01cr@0 1639 cerr << "warning: ignoring query timestamps for non-timestamped database" << endl;
mas01cr@0 1640 usingTimes=0;
mas01cr@0 1641 }
mas01cr@0 1642
mas01cr@0 1643 else if(!usingTimes && (dbH->flags & O2_FLAG_TIMES))
mas01cr@0 1644 cerr << "warning: no timestamps given for query. Ignoring database timestamps." << endl;
mas01cr@0 1645
mas01cr@0 1646 else if(usingTimes && (dbH->flags & O2_FLAG_TIMES)){
mas01cr@0 1647 timesdata = new double[numVectors];
mas01cr@0 1648 assert(timesdata);
mas01cr@0 1649 insertTimeStamps(numVectors, timesFile, timesdata);
mas01cr@0 1650 // Calculate durations of points
mas01cr@0 1651 for(k=0; k<numVectors-1; k++){
mas01cr@0 1652 timesdata[k]=timesdata[k+1]-timesdata[k];
mas01cr@0 1653 meanQdur+=timesdata[k];
mas01cr@0 1654 }
mas01cr@0 1655 meanQdur/=k;
mas01cr@60 1656 if(verbosity>1) {
mas01cr@0 1657 cerr << "mean query file duration: " << meanQdur << endl;
mas01cr@60 1658 }
mas01cr@0 1659 meanDBdur = new double[dbH->numFiles];
mas01cr@0 1660 assert(meanDBdur);
mas01cr@0 1661 for(k=0; k<dbH->numFiles; k++){
mas01cr@0 1662 meanDBdur[k]=0.0;
mas01mc@18 1663 for(j=0; j<trackTable[k]-1 ; j++)
mas01cr@0 1664 meanDBdur[k]+=timesTable[j+1]-timesTable[j];
mas01cr@0 1665 meanDBdur[k]/=j;
mas01cr@0 1666 }
mas01cr@0 1667 }
mas01cr@0 1668
mas01cr@0 1669 if(usingQueryPoint)
mas01cr@0 1670 if(queryPoint>numVectors || queryPoint>numVectors-wL+1)
mas01cr@0 1671 error("queryPoint > numVectors-wL+1 in query");
mas01cr@0 1672 else{
mas01cr@60 1673 if(verbosity>1) {
mas01cr@0 1674 cerr << "query point: " << queryPoint << endl; cerr.flush();
mas01cr@60 1675 }
mas01cr@0 1676 query=query+queryPoint*dbH->dim;
mas01cr@125 1677 qnPtr=qnPtr+queryPoint;
mas01cr@0 1678 numVectors=wL;
mas01cr@0 1679 }
mas01cr@0 1680
mas01mc@20 1681 double ** D = 0; // Differences query and target
mas01cr@0 1682 double ** DD = 0; // Matched filter distance
mas01cr@0 1683
mas01cr@0 1684 D = new double*[numVectors];
mas01cr@0 1685 assert(D);
mas01cr@0 1686 DD = new double*[numVectors];
mas01cr@0 1687 assert(DD);
mas01cr@0 1688
mas01cr@0 1689 gettimeofday(&tv1, NULL);
mas01mc@18 1690 processedTracks=0;
mas01mc@18 1691 unsigned successfulTracks=0;
mas01cr@0 1692
mas01cr@0 1693 double* qp;
mas01cr@0 1694 double* sp;
mas01cr@0 1695 double* dp;
mas01cr@0 1696
mas01mc@18 1697 // build track offset table
mas01mc@18 1698 unsigned *trackOffsetTable = new unsigned[dbH->numFiles];
mas01mc@18 1699 unsigned cumTrack=0;
mas01mc@18 1700 unsigned trackIndexOffset;
mas01cr@0 1701 for(k=0; k<dbH->numFiles;k++){
mas01mc@18 1702 trackOffsetTable[k]=cumTrack;
mas01mc@18 1703 cumTrack+=trackTable[k]*dbH->dim;
mas01cr@0 1704 }
mas01cr@0 1705
mas01cr@0 1706 char nextKey [MAXSTR];
mas01mc@20 1707
mas01mc@20 1708 // chi^2 statistics
mas01mc@20 1709 double sampleCount = 0;
mas01mc@20 1710 double sampleSum = 0;
mas01mc@20 1711 double logSampleSum = 0;
mas01mc@20 1712 double minSample = 1e9;
mas01mc@20 1713 double maxSample = 0;
mas01mc@20 1714
mas01mc@20 1715 // Track loop
mas01mc@18 1716 for(processedTracks=0, track=0 ; processedTracks < dbH->numFiles ; track++, processedTracks++){
mas01cr@0 1717
mas01mc@18 1718 // get trackID from file if using a control file
mas01mc@18 1719 if(trackFile){
mas01mc@18 1720 if(!trackFile->eof()){
mas01mc@18 1721 trackFile->getline(nextKey,MAXSTR);
mas01mc@18 1722 track=getKeyPos(nextKey);
mas01cr@0 1723 }
mas01cr@0 1724 else
mas01cr@0 1725 break;
mas01cr@0 1726 }
mas01mc@12 1727
mas01mc@18 1728 trackOffset=trackOffsetTable[track]; // numDoubles offset
mas01mc@18 1729 trackIndexOffset=trackOffset/dbH->dim; // numVectors offset
mas01cr@0 1730
mas01cr@57 1731 if(sequenceLength<=trackTable[track]){ // test for short sequences
mas01cr@0 1732
mas01cr@60 1733 if(verbosity>7) {
mas01mc@18 1734 cerr << track << "." << trackIndexOffset << "." << trackTable[track] << " | ";cerr.flush();
mas01cr@60 1735 }
mas01cr@0 1736
mas01mc@20 1737 // Sum products matrix
mas01cr@0 1738 for(j=0; j<numVectors;j++){
mas01mc@18 1739 D[j]=new double[trackTable[track]];
mas01cr@0 1740 assert(D[j]);
mas01cr@0 1741
mas01cr@0 1742 }
mas01cr@0 1743
mas01cr@0 1744 // Matched filter matrix
mas01cr@0 1745 for(j=0; j<numVectors;j++){
mas01mc@18 1746 DD[j]=new double[trackTable[track]];
mas01cr@0 1747 assert(DD[j]);
mas01cr@0 1748 }
mas01cr@0 1749
mas01mc@20 1750 // Dot product
mas01cr@0 1751 for(j=0; j<numVectors; j++)
mas01mc@18 1752 for(k=0; k<trackTable[track]; k++){
mas01cr@0 1753 qp=query+j*dbH->dim;
mas01mc@18 1754 sp=dataBuf+trackOffset+k*dbH->dim;
mas01cr@0 1755 DD[j][k]=0.0; // Initialize matched filter array
mas01cr@0 1756 dp=&D[j][k]; // point to correlation cell j,k
mas01cr@0 1757 *dp=0.0; // initialize correlation cell
mas01cr@0 1758 l=dbH->dim; // size of vectors
mas01cr@0 1759 while(l--)
mas01cr@0 1760 *dp+=*qp++**sp++;
mas01cr@0 1761 }
mas01cr@0 1762
mas01cr@0 1763 // Matched Filter
mas01cr@0 1764 // HOP SIZE == 1
mas01cr@0 1765 double* spd;
mas01cr@0 1766 if(HOP_SIZE==1){ // HOP_SIZE = shingleHop
mas01cr@0 1767 for(w=0; w<wL; w++)
mas01cr@0 1768 for(j=0; j<numVectors-w; j++){
mas01cr@0 1769 sp=DD[j];
mas01cr@0 1770 spd=D[j+w]+w;
mas01mc@18 1771 k=trackTable[track]-w;
mas01cr@0 1772 while(k--)
mas01cr@0 1773 *sp+++=*spd++;
mas01cr@0 1774 }
mas01cr@0 1775 }
mas01mc@20 1776
mas01cr@0 1777 else{ // HOP_SIZE != 1
mas01cr@0 1778 for(w=0; w<wL; w++)
mas01cr@0 1779 for(j=0; j<numVectors-w; j+=HOP_SIZE){
mas01cr@0 1780 sp=DD[j];
mas01cr@0 1781 spd=D[j+w]+w;
mas01mc@18 1782 for(k=0; k<trackTable[track]-w; k+=HOP_SIZE){
mas01cr@0 1783 *sp+=*spd;
mas01cr@0 1784 sp+=HOP_SIZE;
mas01cr@0 1785 spd+=HOP_SIZE;
mas01cr@0 1786 }
mas01cr@0 1787 }
mas01cr@0 1788 }
mas01cr@0 1789
mas01cr@60 1790 if(verbosity>3 && usingTimes) {
mas01mc@18 1791 cerr << "meanQdur=" << meanQdur << " meanDBdur=" << meanDBdur[track] << endl;
mas01cr@0 1792 cerr.flush();
mas01cr@0 1793 }
mas01cr@0 1794
mas01cr@0 1795 if(!usingTimes ||
mas01cr@0 1796 (usingTimes
mas01mc@18 1797 && fabs(meanDBdur[track]-meanQdur)<meanQdur*timesTol)){
mas01cr@0 1798
mas01cr@60 1799 if(verbosity>3 && usingTimes) {
mas01cr@0 1800 cerr << "within duration tolerance." << endl;
mas01cr@0 1801 cerr.flush();
mas01cr@0 1802 }
mas01cr@0 1803
mas01cr@0 1804 // Search for minimum distance by shingles (concatenated vectors)
mas01cr@53 1805 for(j=0;j<=numVectors-wL;j+=HOP_SIZE)
mas01cr@53 1806 for(k=0;k<=trackTable[track]-wL;k+=HOP_SIZE){
mas01cr@125 1807 thisDist=2-(2/(qnPtr[j]*sNorm[trackIndexOffset+k]))*DD[j][k];
mas01cr@60 1808 if(verbosity>10) {
mas01cr@125 1809 cerr << thisDist << " " << qnPtr[j] << " " << sNorm[trackIndexOffset+k] << endl;
mas01cr@60 1810 }
mas01mc@20 1811 // Gather chi^2 statistics
mas01mc@20 1812 if(thisDist<minSample)
mas01mc@20 1813 minSample=thisDist;
mas01mc@20 1814 else if(thisDist>maxSample)
mas01mc@20 1815 maxSample=thisDist;
mas01mc@20 1816 if(thisDist>1e-9){
mas01mc@20 1817 sampleCount++;
mas01mc@20 1818 sampleSum+=thisDist;
mas01mc@20 1819 logSampleSum+=log(thisDist);
mas01mc@20 1820 }
mas01mc@20 1821
mas01cr@125 1822 // diffL2 = fabs(qnPtr[j] - sNorm[trackIndexOffset+k]);
mas01cr@0 1823 // Power test
mas01cr@0 1824 if(!USE_THRESH ||
mas01cr@0 1825 // Threshold on mean L2 of Q and S sequences
mas01cr@125 1826 (USE_THRESH && qnPtr[j]>SILENCE_THRESH && sNorm[trackIndexOffset+k]>SILENCE_THRESH &&
mas01cr@0 1827 // Are both query and target windows above mean energy?
mas01cr@125 1828 (qnPtr[j]>qMeanL2*.25 && sNorm[trackIndexOffset+k]>sMeanL2[track]*.25))) // && diffL2 < DIFF_THRESH )))
mas01mc@20 1829 thisDist=thisDist; // Computed above
mas01cr@0 1830 else
mas01mc@20 1831 thisDist=1000000.0;
mas01mc@20 1832
mas01mc@20 1833 // k-NN match algorithm
mas01cr@58 1834 m=pointNN;
mas01mc@20 1835 while(m--){
mas01mc@20 1836 if(thisDist<=distances[m])
mas01mc@20 1837 if(m==0 || thisDist>=distances[m-1]){
mas01cr@0 1838 // Shuffle distances up the list
mas01cr@0 1839 for(l=pointNN-1; l>m; l--){
mas01cr@0 1840 distances[l]=distances[l-1];
mas01cr@0 1841 qIndexes[l]=qIndexes[l-1];
mas01cr@0 1842 sIndexes[l]=sIndexes[l-1];
mas01cr@0 1843 }
mas01cr@0 1844 distances[m]=thisDist;
mas01cr@0 1845 if(usingQueryPoint)
mas01cr@0 1846 qIndexes[m]=queryPoint;
mas01cr@0 1847 else
mas01cr@0 1848 qIndexes[m]=j;
mas01cr@0 1849 sIndexes[m]=k;
mas01cr@0 1850 break;
mas01mc@20 1851 }
mas01cr@0 1852 }
mas01cr@0 1853 }
mas01cr@0 1854 // Calculate the mean of the N-Best matches
mas01cr@0 1855 thisDist=0.0;
mas01cr@53 1856 for(m=0; m<pointNN; m++) {
mas01cr@53 1857 if (distances[m] == 1000000.0) break;
mas01mc@20 1858 thisDist+=distances[m];
mas01cr@53 1859 }
mas01cr@53 1860 thisDist/=m;
mas01cr@0 1861
mas01mc@12 1862 // Let's see the distances then...
mas01cr@60 1863 if(verbosity>3) {
mas01mc@18 1864 cerr << fileTable+track*O2_FILETABLESIZE << " " << thisDist << endl;
mas01cr@60 1865 }
mas01mc@12 1866
mas01mc@20 1867
mas01mc@18 1868 // All the track stuff goes here
mas01cr@58 1869 n=trackNN;
mas01cr@0 1870 while(n--){
mas01mc@20 1871 if(thisDist<=trackDistances[n]){
mas01mc@20 1872 if((n==0 || thisDist>=trackDistances[n-1])){
mas01cr@0 1873 // Copy all values above up the queue
mas01mc@18 1874 for( l=trackNN-1 ; l > n ; l--){
mas01mc@18 1875 trackDistances[l]=trackDistances[l-1];
mas01mc@18 1876 trackQIndexes[l]=trackQIndexes[l-1];
mas01mc@18 1877 trackSIndexes[l]=trackSIndexes[l-1];
mas01mc@18 1878 trackIDs[l]=trackIDs[l-1];
mas01cr@0 1879 }
mas01mc@18 1880 trackDistances[n]=thisDist;
mas01mc@18 1881 trackQIndexes[n]=qIndexes[0];
mas01mc@18 1882 trackSIndexes[n]=sIndexes[0];
mas01mc@18 1883 successfulTracks++;
mas01mc@18 1884 trackIDs[n]=track;
mas01cr@0 1885 break;
mas01cr@0 1886 }
mas01cr@0 1887 }
mas01cr@0 1888 else
mas01cr@0 1889 break;
mas01cr@0 1890 }
mas01cr@0 1891 } // Duration match
mas01mc@20 1892
mas01mc@18 1893 // Clean up current track
mas01cr@0 1894 if(D!=NULL){
mas01cr@0 1895 for(j=0; j<numVectors; j++)
mas01cr@0 1896 delete[] D[j];
mas01cr@0 1897 }
mas01cr@0 1898
mas01cr@0 1899 if(DD!=NULL){
mas01cr@0 1900 for(j=0; j<numVectors; j++)
mas01cr@0 1901 delete[] DD[j];
mas01cr@0 1902 }
mas01cr@0 1903 }
mas01mc@20 1904 // per-track reset array values
mas01mc@20 1905 for(unsigned k=0; k<pointNN; k++){
mas01mc@20 1906 distances[k]=1.0e6;
mas01mc@20 1907 qIndexes[k]=~0;
mas01mc@20 1908 sIndexes[k]=~0;
mas01mc@20 1909 }
mas01cr@0 1910 }
mas01cr@0 1911
mas01cr@0 1912 gettimeofday(&tv2,NULL);
mas01cr@60 1913 if(verbosity>1) {
mas01mc@18 1914 cerr << endl << "processed tracks :" << processedTracks << " matched tracks: " << successfulTracks << " elapsed time:"
mas01cr@0 1915 << ( tv2.tv_sec*1000 + tv2.tv_usec/1000 ) - ( tv1.tv_sec*1000+tv1.tv_usec/1000 ) << " msec" << endl;
mas01mc@20 1916 cerr << "sampleCount: " << sampleCount << " sampleSum: " << sampleSum << " logSampleSum: " << logSampleSum
mas01mc@20 1917 << " minSample: " << minSample << " maxSample: " << maxSample << endl;
mas01mc@20 1918 }
mas01cr@133 1919 if(adbQueryResponse==0){
mas01cr@60 1920 if(verbosity>1) {
mas01cr@0 1921 cerr<<endl;
mas01cr@60 1922 }
mas01cr@0 1923 // Output answer
mas01cr@0 1924 // Loop over nearest neighbours
mas01mc@18 1925 for(k=0; k < min(trackNN,successfulTracks); k++)
mas01mc@20 1926 cout << fileTable+trackIDs[k]*O2_FILETABLESIZE << " " << trackDistances[k] << " "
mas01mc@20 1927 << trackQIndexes[k] << " " << trackSIndexes[k] << endl;
mas01cr@0 1928 }
mas01cr@0 1929 else{ // Process Web Services Query
mas01mc@18 1930 int listLen = min(trackNN, processedTracks);
mas01cr@133 1931 adbQueryResponse->result.__sizeRlist=listLen;
mas01cr@133 1932 adbQueryResponse->result.__sizeDist=listLen;
mas01cr@133 1933 adbQueryResponse->result.__sizeQpos=listLen;
mas01cr@133 1934 adbQueryResponse->result.__sizeSpos=listLen;
mas01cr@133 1935 adbQueryResponse->result.Rlist= new char*[listLen];
mas01cr@133 1936 adbQueryResponse->result.Dist = new double[listLen];
mas01cr@133 1937 adbQueryResponse->result.Qpos = new unsigned int[listLen];
mas01cr@133 1938 adbQueryResponse->result.Spos = new unsigned int[listLen];
mas01cr@133 1939 for(k=0; k<(unsigned)adbQueryResponse->result.__sizeRlist; k++){
mas01cr@133 1940 adbQueryResponse->result.Rlist[k]=new char[O2_MAXFILESTR];
mas01cr@133 1941 adbQueryResponse->result.Dist[k]=trackDistances[k];
mas01cr@133 1942 adbQueryResponse->result.Qpos[k]=trackQIndexes[k];
mas01cr@133 1943 adbQueryResponse->result.Spos[k]=trackSIndexes[k];
mas01cr@133 1944 sprintf(adbQueryResponse->result.Rlist[k], "%s", fileTable+trackIDs[k]*O2_FILETABLESIZE);
mas01cr@0 1945 }
mas01cr@0 1946 }
mas01cr@0 1947
mas01cr@0 1948
mas01cr@0 1949 // Clean up
mas01mc@18 1950 if(trackOffsetTable)
mas01mc@20 1951 delete[] trackOffsetTable;
mas01cr@0 1952 if(queryCopy)
mas01mc@20 1953 delete[] queryCopy;
mas01cr@121 1954 if(qNorm)
mas01cr@121 1955 delete[] qNorm;
mas01cr@121 1956 if(sNorm)
mas01cr@121 1957 delete[] sNorm;
mas01cr@121 1958 if(sMeanL2)
mas01cr@121 1959 delete[] sMeanL2;
mas01cr@0 1960 if(D)
mas01cr@0 1961 delete[] D;
mas01cr@0 1962 if(DD)
mas01cr@0 1963 delete[] DD;
mas01cr@0 1964 if(timesdata)
mas01mc@20 1965 delete[] timesdata;
mas01cr@0 1966 if(meanDBdur)
mas01mc@20 1967 delete[] meanDBdur;
mas01cr@0 1968
mas01cr@0 1969
mas01cr@0 1970 }
mas01cr@0 1971
mas01mc@20 1972 // Radius search between query and target tracks
mas01mc@20 1973 // efficient implementation based on matched filter
mas01mc@20 1974 // assumes normed shingles
mas01mc@20 1975 // outputs count of retrieved shingles, max retreived = one shingle per query shingle per track
mas01cr@133 1976 void audioDB::trackSequenceQueryRad(const char* dbName, const char* inFile, adb__queryResponse *adbQueryResponse){
mas01mc@17 1977
mas01cr@27 1978 initTables(dbName, 0, inFile);
mas01mc@17 1979
mas01mc@17 1980 // For each input vector, find the closest pointNN matching output vectors and report
mas01mc@17 1981 // we use stdout in this stub version
mas01mc@17 1982 unsigned numVectors = (statbuf.st_size-sizeof(int))/(sizeof(double)*dbH->dim);
mas01mc@17 1983 double* query = (double*)(indata+sizeof(int));
mas01mc@17 1984 double* queryCopy = 0;
mas01mc@17 1985
mas01mc@17 1986 double qMeanL2;
mas01mc@17 1987 double* sMeanL2;
mas01mc@17 1988
mas01mc@17 1989 unsigned USE_THRESH=0;
mas01mc@17 1990 double SILENCE_THRESH=0;
mas01mc@17 1991 double DIFF_THRESH=0;
mas01mc@17 1992
mas01mc@17 1993 if(!(dbH->flags & O2_FLAG_L2NORM) )
mas01mc@17 1994 error("Database must be L2 normed for sequence query","use -l2norm");
mas01mc@17 1995
mas01cr@60 1996 if(verbosity>1) {
mas01mc@17 1997 cerr << "performing norms ... "; cerr.flush();
mas01cr@60 1998 }
mas01mc@17 1999 unsigned dbVectors = dbH->length/(sizeof(double)*dbH->dim);
mas01mc@18 2000
mas01mc@17 2001 // Make a copy of the query
mas01mc@17 2002 queryCopy = new double[numVectors*dbH->dim];
mas01mc@17 2003 memcpy(queryCopy, query, numVectors*dbH->dim*sizeof(double));
mas01mc@17 2004 qNorm = new double[numVectors];
mas01mc@17 2005 sNorm = new double[dbVectors];
mas01mc@17 2006 sMeanL2=new double[dbH->numFiles];
mas01mc@17 2007 assert(qNorm&&sNorm&&queryCopy&&sMeanL2&&sequenceLength);
mas01mc@17 2008 unitNorm(queryCopy, dbH->dim, numVectors, qNorm);
mas01mc@17 2009 query = queryCopy;
mas01mc@18 2010
mas01mc@17 2011 // Make norm measurements relative to sequenceLength
mas01mc@17 2012 unsigned w = sequenceLength-1;
mas01mc@17 2013 unsigned i,j;
mas01mc@17 2014 double* ps;
mas01mc@17 2015 double tmp1,tmp2;
mas01mc@18 2016
mas01mc@17 2017 // Copy the L2 norm values to core to avoid disk random access later on
mas01mc@17 2018 memcpy(sNorm, l2normTable, dbVectors*sizeof(double));
mas01mc@17 2019 double* snPtr = sNorm;
mas01cr@125 2020 double* qnPtr = qNorm;
mas01mc@17 2021 for(i=0; i<dbH->numFiles; i++){
mas01mc@18 2022 if(trackTable[i]>=sequenceLength){
mas01mc@17 2023 tmp1=*snPtr;
mas01mc@17 2024 j=1;
mas01mc@17 2025 w=sequenceLength-1;
mas01mc@17 2026 while(w--)
mas01mc@17 2027 *snPtr+=snPtr[j++];
mas01mc@17 2028 ps = snPtr+1;
mas01mc@18 2029 w=trackTable[i]-sequenceLength; // +1 - 1
mas01mc@17 2030 while(w--){
mas01mc@17 2031 tmp2=*ps;
mas01mc@17 2032 *ps=*(ps-1)-tmp1+*(ps+sequenceLength-1);
mas01mc@17 2033 tmp1=tmp2;
mas01mc@17 2034 ps++;
mas01mc@17 2035 }
mas01mc@17 2036 ps = snPtr;
mas01mc@18 2037 w=trackTable[i]-sequenceLength+1;
mas01mc@17 2038 while(w--){
mas01mc@17 2039 *ps=sqrt(*ps);
mas01mc@17 2040 ps++;
mas01mc@17 2041 }
mas01mc@17 2042 }
mas01mc@18 2043 snPtr+=trackTable[i];
mas01mc@17 2044 }
mas01mc@17 2045
mas01mc@17 2046 double* pn = sMeanL2;
mas01mc@17 2047 w=dbH->numFiles;
mas01mc@17 2048 while(w--)
mas01mc@17 2049 *pn++=0.0;
mas01mc@17 2050 ps=sNorm;
mas01mc@18 2051 unsigned processedTracks=0;
mas01mc@17 2052 for(i=0; i<dbH->numFiles; i++){
mas01mc@18 2053 if(trackTable[i]>sequenceLength-1){
mas01cr@70 2054 w = trackTable[i]-sequenceLength+1;
mas01mc@17 2055 pn = sMeanL2+i;
mas01mc@17 2056 *pn=0;
mas01mc@17 2057 while(w--)
mas01mc@17 2058 if(*ps>0)
mas01mc@17 2059 *pn+=*ps++;
mas01cr@70 2060 *pn/=trackTable[i]-sequenceLength+1;
mas01mc@17 2061 SILENCE_THRESH+=*pn;
mas01mc@18 2062 processedTracks++;
mas01mc@17 2063 }
mas01mc@18 2064 ps = sNorm + trackTable[i];
mas01mc@17 2065 }
mas01cr@60 2066 if(verbosity>1) {
mas01mc@18 2067 cerr << "processedTracks: " << processedTracks << endl;
mas01cr@60 2068 }
mas01mc@17 2069
mas01mc@18 2070 SILENCE_THRESH/=processedTracks;
mas01mc@17 2071 USE_THRESH=1; // Turn thresholding on
mas01mc@18 2072 DIFF_THRESH=SILENCE_THRESH; // mean shingle power
mas01mc@17 2073 SILENCE_THRESH/=5; // 20% of the mean shingle power is SILENCE
mas01cr@60 2074 if(verbosity>4) {
mas01mc@17 2075 cerr << "silence thresh: " << SILENCE_THRESH;
mas01cr@60 2076 }
mas01mc@17 2077 w=sequenceLength-1;
mas01mc@17 2078 i=1;
mas01cr@125 2079 tmp1=*qnPtr;
mas01mc@17 2080 while(w--)
mas01cr@125 2081 *qnPtr+=qnPtr[i++];
mas01cr@125 2082 ps = qnPtr+1;
mas01mc@17 2083 w=numVectors-sequenceLength; // +1 -1
mas01mc@17 2084 while(w--){
mas01mc@17 2085 tmp2=*ps;
mas01mc@17 2086 *ps=*(ps-1)-tmp1+*(ps+sequenceLength-1);
mas01mc@17 2087 tmp1=tmp2;
mas01mc@17 2088 ps++;
mas01mc@17 2089 }
mas01cr@125 2090 ps = qnPtr;
mas01mc@17 2091 qMeanL2 = 0;
mas01mc@17 2092 w=numVectors-sequenceLength+1;
mas01mc@17 2093 while(w--){
mas01mc@17 2094 *ps=sqrt(*ps);
mas01mc@17 2095 qMeanL2+=*ps++;
mas01mc@17 2096 }
mas01mc@17 2097 qMeanL2 /= numVectors-sequenceLength+1;
mas01mc@17 2098
mas01cr@60 2099 if(verbosity>1) {
mas01mc@17 2100 cerr << "done." << endl;
mas01cr@60 2101 }
mas01mc@17 2102
mas01cr@60 2103 if(verbosity>1) {
mas01mc@18 2104 cerr << "matching tracks..." << endl;
mas01cr@60 2105 }
mas01mc@17 2106
mas01mc@17 2107 assert(pointNN>0 && pointNN<=O2_MAXNN);
mas01mc@18 2108 assert(trackNN>0 && trackNN<=O2_MAXNN);
mas01mc@17 2109
mas01mc@17 2110 // Make temporary dynamic memory for results
mas01mc@18 2111 double trackDistances[trackNN];
mas01mc@18 2112 unsigned trackIDs[trackNN];
mas01mc@18 2113 unsigned trackQIndexes[trackNN];
mas01mc@18 2114 unsigned trackSIndexes[trackNN];
mas01mc@17 2115
mas01mc@17 2116 double distances[pointNN];
mas01mc@17 2117 unsigned qIndexes[pointNN];
mas01mc@17 2118 unsigned sIndexes[pointNN];
mas01mc@17 2119
mas01mc@17 2120
mas01cr@59 2121 unsigned k,l,n,track,trackOffset=0, HOP_SIZE=sequenceHop, wL=sequenceLength;
mas01mc@17 2122 double thisDist;
mas01mc@17 2123
mas01mc@17 2124 for(k=0; k<pointNN; k++){
mas01mc@17 2125 distances[k]=0.0;
mas01mc@17 2126 qIndexes[k]=~0;
mas01mc@17 2127 sIndexes[k]=~0;
mas01mc@17 2128 }
mas01mc@17 2129
mas01mc@18 2130 for(k=0; k<trackNN; k++){
mas01mc@18 2131 trackDistances[k]=0.0;
mas01mc@18 2132 trackQIndexes[k]=~0;
mas01mc@18 2133 trackSIndexes[k]=~0;
mas01mc@18 2134 trackIDs[k]=~0;
mas01mc@17 2135 }
mas01mc@17 2136
mas01mc@17 2137 // Timestamp and durations processing
mas01mc@17 2138 double meanQdur = 0;
mas01mc@17 2139 double* timesdata = 0;
mas01mc@17 2140 double* meanDBdur = 0;
mas01mc@17 2141
mas01mc@17 2142 if(usingTimes && !(dbH->flags & O2_FLAG_TIMES)){
mas01mc@17 2143 cerr << "warning: ignoring query timestamps for non-timestamped database" << endl;
mas01mc@17 2144 usingTimes=0;
mas01mc@17 2145 }
mas01mc@17 2146
mas01mc@17 2147 else if(!usingTimes && (dbH->flags & O2_FLAG_TIMES))
mas01mc@17 2148 cerr << "warning: no timestamps given for query. Ignoring database timestamps." << endl;
mas01mc@17 2149
mas01mc@17 2150 else if(usingTimes && (dbH->flags & O2_FLAG_TIMES)){
mas01mc@17 2151 timesdata = new double[numVectors];
mas01mc@17 2152 assert(timesdata);
mas01mc@17 2153 insertTimeStamps(numVectors, timesFile, timesdata);
mas01mc@17 2154 // Calculate durations of points
mas01mc@17 2155 for(k=0; k<numVectors-1; k++){
mas01mc@17 2156 timesdata[k]=timesdata[k+1]-timesdata[k];
mas01mc@17 2157 meanQdur+=timesdata[k];
mas01mc@17 2158 }
mas01mc@17 2159 meanQdur/=k;
mas01cr@60 2160 if(verbosity>1) {
mas01mc@17 2161 cerr << "mean query file duration: " << meanQdur << endl;
mas01cr@60 2162 }
mas01mc@17 2163 meanDBdur = new double[dbH->numFiles];
mas01mc@17 2164 assert(meanDBdur);
mas01mc@17 2165 for(k=0; k<dbH->numFiles; k++){
mas01mc@17 2166 meanDBdur[k]=0.0;
mas01mc@18 2167 for(j=0; j<trackTable[k]-1 ; j++)
mas01mc@17 2168 meanDBdur[k]+=timesTable[j+1]-timesTable[j];
mas01mc@17 2169 meanDBdur[k]/=j;
mas01mc@17 2170 }
mas01mc@17 2171 }
mas01mc@17 2172
mas01mc@17 2173 if(usingQueryPoint)
mas01mc@17 2174 if(queryPoint>numVectors || queryPoint>numVectors-wL+1)
mas01mc@17 2175 error("queryPoint > numVectors-wL+1 in query");
mas01mc@17 2176 else{
mas01cr@60 2177 if(verbosity>1) {
mas01mc@17 2178 cerr << "query point: " << queryPoint << endl; cerr.flush();
mas01cr@60 2179 }
mas01mc@17 2180 query=query+queryPoint*dbH->dim;
mas01cr@125 2181 qnPtr=qnPtr+queryPoint;
mas01mc@17 2182 numVectors=wL;
mas01mc@17 2183 }
mas01mc@17 2184
mas01mc@17 2185 double ** D = 0; // Differences query and target
mas01mc@17 2186 double ** DD = 0; // Matched filter distance
mas01mc@17 2187
mas01mc@17 2188 D = new double*[numVectors];
mas01mc@17 2189 assert(D);
mas01mc@17 2190 DD = new double*[numVectors];
mas01mc@17 2191 assert(DD);
mas01mc@17 2192
mas01mc@17 2193 gettimeofday(&tv1, NULL);
mas01mc@18 2194 processedTracks=0;
mas01mc@18 2195 unsigned successfulTracks=0;
mas01mc@17 2196
mas01mc@17 2197 double* qp;
mas01mc@17 2198 double* sp;
mas01mc@17 2199 double* dp;
mas01mc@17 2200
mas01mc@18 2201 // build track offset table
mas01mc@18 2202 unsigned *trackOffsetTable = new unsigned[dbH->numFiles];
mas01mc@18 2203 unsigned cumTrack=0;
mas01mc@18 2204 unsigned trackIndexOffset;
mas01mc@17 2205 for(k=0; k<dbH->numFiles;k++){
mas01mc@18 2206 trackOffsetTable[k]=cumTrack;
mas01mc@18 2207 cumTrack+=trackTable[k]*dbH->dim;
mas01mc@17 2208 }
mas01mc@17 2209
mas01mc@17 2210 char nextKey [MAXSTR];
mas01mc@17 2211
mas01mc@17 2212 // chi^2 statistics
mas01mc@17 2213 double sampleCount = 0;
mas01mc@17 2214 double sampleSum = 0;
mas01mc@17 2215 double logSampleSum = 0;
mas01mc@17 2216 double minSample = 1e9;
mas01mc@17 2217 double maxSample = 0;
mas01mc@17 2218
mas01mc@17 2219 // Track loop
mas01mc@18 2220 for(processedTracks=0, track=0 ; processedTracks < dbH->numFiles ; track++, processedTracks++){
mas01mc@17 2221
mas01mc@18 2222 // get trackID from file if using a control file
mas01mc@18 2223 if(trackFile){
mas01mc@18 2224 if(!trackFile->eof()){
mas01mc@18 2225 trackFile->getline(nextKey,MAXSTR);
mas01mc@18 2226 track=getKeyPos(nextKey);
mas01mc@17 2227 }
mas01mc@17 2228 else
mas01mc@17 2229 break;
mas01mc@17 2230 }
mas01mc@17 2231
mas01mc@18 2232 trackOffset=trackOffsetTable[track]; // numDoubles offset
mas01mc@18 2233 trackIndexOffset=trackOffset/dbH->dim; // numVectors offset
mas01mc@17 2234
mas01cr@70 2235 if(sequenceLength<=trackTable[track]){ // test for short sequences
mas01mc@17 2236
mas01cr@60 2237 if(verbosity>7) {
mas01mc@18 2238 cerr << track << "." << trackIndexOffset << "." << trackTable[track] << " | ";cerr.flush();
mas01cr@60 2239 }
mas01cr@60 2240
mas01mc@17 2241 // Sum products matrix
mas01mc@17 2242 for(j=0; j<numVectors;j++){
mas01mc@18 2243 D[j]=new double[trackTable[track]];
mas01mc@17 2244 assert(D[j]);
mas01mc@17 2245
mas01mc@17 2246 }
mas01mc@17 2247
mas01mc@17 2248 // Matched filter matrix
mas01mc@17 2249 for(j=0; j<numVectors;j++){
mas01mc@18 2250 DD[j]=new double[trackTable[track]];
mas01mc@17 2251 assert(DD[j]);
mas01mc@17 2252 }
mas01mc@17 2253
mas01mc@17 2254 // Dot product
mas01mc@17 2255 for(j=0; j<numVectors; j++)
mas01mc@18 2256 for(k=0; k<trackTable[track]; k++){
mas01mc@17 2257 qp=query+j*dbH->dim;
mas01mc@18 2258 sp=dataBuf+trackOffset+k*dbH->dim;
mas01mc@17 2259 DD[j][k]=0.0; // Initialize matched filter array
mas01mc@17 2260 dp=&D[j][k]; // point to correlation cell j,k
mas01mc@17 2261 *dp=0.0; // initialize correlation cell
mas01mc@17 2262 l=dbH->dim; // size of vectors
mas01mc@17 2263 while(l--)
mas01mc@17 2264 *dp+=*qp++**sp++;
mas01mc@17 2265 }
mas01mc@17 2266
mas01mc@17 2267 // Matched Filter
mas01mc@17 2268 // HOP SIZE == 1
mas01mc@17 2269 double* spd;
mas01mc@17 2270 if(HOP_SIZE==1){ // HOP_SIZE = shingleHop
mas01mc@17 2271 for(w=0; w<wL; w++)
mas01mc@17 2272 for(j=0; j<numVectors-w; j++){
mas01mc@17 2273 sp=DD[j];
mas01mc@17 2274 spd=D[j+w]+w;
mas01mc@18 2275 k=trackTable[track]-w;
mas01mc@17 2276 while(k--)
mas01mc@17 2277 *sp+++=*spd++;
mas01mc@17 2278 }
mas01mc@17 2279 }
mas01mc@17 2280
mas01mc@17 2281 else{ // HOP_SIZE != 1
mas01mc@17 2282 for(w=0; w<wL; w++)
mas01mc@17 2283 for(j=0; j<numVectors-w; j+=HOP_SIZE){
mas01mc@17 2284 sp=DD[j];
mas01mc@17 2285 spd=D[j+w]+w;
mas01mc@18 2286 for(k=0; k<trackTable[track]-w; k+=HOP_SIZE){
mas01mc@17 2287 *sp+=*spd;
mas01mc@17 2288 sp+=HOP_SIZE;
mas01mc@17 2289 spd+=HOP_SIZE;
mas01mc@17 2290 }
mas01mc@17 2291 }
mas01mc@17 2292 }
mas01mc@17 2293
mas01cr@60 2294 if(verbosity>3 && usingTimes) {
mas01mc@18 2295 cerr << "meanQdur=" << meanQdur << " meanDBdur=" << meanDBdur[track] << endl;
mas01mc@17 2296 cerr.flush();
mas01mc@17 2297 }
mas01mc@17 2298
mas01mc@17 2299 if(!usingTimes ||
mas01mc@17 2300 (usingTimes
mas01mc@18 2301 && fabs(meanDBdur[track]-meanQdur)<meanQdur*timesTol)){
mas01mc@17 2302
mas01cr@60 2303 if(verbosity>3 && usingTimes) {
mas01mc@17 2304 cerr << "within duration tolerance." << endl;
mas01mc@17 2305 cerr.flush();
mas01mc@17 2306 }
mas01mc@17 2307
mas01mc@17 2308 // Search for minimum distance by shingles (concatenated vectors)
mas01cr@70 2309 for(j=0;j<=numVectors-wL;j+=HOP_SIZE)
mas01cr@70 2310 for(k=0;k<=trackTable[track]-wL;k+=HOP_SIZE){
mas01cr@125 2311 thisDist=2-(2/(qnPtr[j]*sNorm[trackIndexOffset+k]))*DD[j][k];
mas01cr@60 2312 if(verbosity>10) {
mas01cr@125 2313 cerr << thisDist << " " << qnPtr[j] << " " << sNorm[trackIndexOffset+k] << endl;
mas01cr@60 2314 }
mas01mc@17 2315 // Gather chi^2 statistics
mas01mc@17 2316 if(thisDist<minSample)
mas01mc@17 2317 minSample=thisDist;
mas01mc@17 2318 else if(thisDist>maxSample)
mas01mc@17 2319 maxSample=thisDist;
mas01mc@17 2320 if(thisDist>1e-9){
mas01mc@17 2321 sampleCount++;
mas01mc@17 2322 sampleSum+=thisDist;
mas01mc@17 2323 logSampleSum+=log(thisDist);
mas01mc@17 2324 }
mas01mc@17 2325
mas01cr@125 2326 // diffL2 = fabs(qnPtr[j] - sNorm[trackIndexOffset+k]);
mas01mc@17 2327 // Power test
mas01mc@17 2328 if(!USE_THRESH ||
mas01mc@17 2329 // Threshold on mean L2 of Q and S sequences
mas01cr@125 2330 (USE_THRESH && qnPtr[j]>SILENCE_THRESH && sNorm[trackIndexOffset+k]>SILENCE_THRESH &&
mas01mc@17 2331 // Are both query and target windows above mean energy?
mas01cr@125 2332 (qnPtr[j]>qMeanL2*.25 && sNorm[trackIndexOffset+k]>sMeanL2[track]*.25))) // && diffL2 < DIFF_THRESH )))
mas01mc@17 2333 thisDist=thisDist; // Computed above
mas01mc@17 2334 else
mas01mc@17 2335 thisDist=1000000.0;
mas01mc@17 2336 if(thisDist>=0 && thisDist<=radius){
mas01mc@17 2337 distances[0]++; // increment count
mas01mc@18 2338 break; // only need one track point per query point
mas01mc@17 2339 }
mas01mc@17 2340 }
mas01mc@17 2341 // How many points were below threshold ?
mas01mc@17 2342 thisDist=distances[0];
mas01mc@17 2343
mas01mc@17 2344 // Let's see the distances then...
mas01cr@60 2345 if(verbosity>3) {
mas01mc@18 2346 cerr << fileTable+track*O2_FILETABLESIZE << " " << thisDist << endl;
mas01cr@60 2347 }
mas01mc@17 2348
mas01mc@18 2349 // All the track stuff goes here
mas01mc@18 2350 n=trackNN;
mas01mc@17 2351 while(n--){
mas01mc@18 2352 if(thisDist>trackDistances[n]){
mas01mc@18 2353 if((n==0 || thisDist<=trackDistances[n-1])){
mas01mc@17 2354 // Copy all values above up the queue
mas01mc@18 2355 for( l=trackNN-1 ; l > n ; l--){
mas01mc@18 2356 trackDistances[l]=trackDistances[l-1];
mas01mc@18 2357 trackQIndexes[l]=trackQIndexes[l-1];
mas01mc@18 2358 trackSIndexes[l]=trackSIndexes[l-1];
mas01mc@18 2359 trackIDs[l]=trackIDs[l-1];
mas01mc@17 2360 }
mas01mc@18 2361 trackDistances[n]=thisDist;
mas01mc@18 2362 trackQIndexes[n]=qIndexes[0];
mas01mc@18 2363 trackSIndexes[n]=sIndexes[0];
mas01mc@18 2364 successfulTracks++;
mas01mc@18 2365 trackIDs[n]=track;
mas01mc@17 2366 break;
mas01mc@17 2367 }
mas01mc@17 2368 }
mas01mc@17 2369 else
mas01mc@17 2370 break;
mas01mc@17 2371 }
mas01mc@17 2372 } // Duration match
mas01mc@17 2373
mas01mc@18 2374 // Clean up current track
mas01mc@17 2375 if(D!=NULL){
mas01mc@17 2376 for(j=0; j<numVectors; j++)
mas01mc@17 2377 delete[] D[j];
mas01mc@17 2378 }
mas01mc@17 2379
mas01mc@17 2380 if(DD!=NULL){
mas01mc@17 2381 for(j=0; j<numVectors; j++)
mas01mc@17 2382 delete[] DD[j];
mas01mc@17 2383 }
mas01mc@17 2384 }
mas01mc@18 2385 // per-track reset array values
mas01mc@17 2386 for(unsigned k=0; k<pointNN; k++){
mas01mc@17 2387 distances[k]=0.0;
mas01mc@17 2388 qIndexes[k]=~0;
mas01mc@17 2389 sIndexes[k]=~0;
mas01mc@17 2390 }
mas01mc@17 2391 }
mas01mc@17 2392
mas01mc@17 2393 gettimeofday(&tv2,NULL);
mas01cr@60 2394 if(verbosity>1) {
mas01mc@18 2395 cerr << endl << "processed tracks :" << processedTracks << " matched tracks: " << successfulTracks << " elapsed time:"
mas01mc@17 2396 << ( tv2.tv_sec*1000 + tv2.tv_usec/1000 ) - ( tv1.tv_sec*1000+tv1.tv_usec/1000 ) << " msec" << endl;
mas01mc@17 2397 cerr << "sampleCount: " << sampleCount << " sampleSum: " << sampleSum << " logSampleSum: " << logSampleSum
mas01mc@17 2398 << " minSample: " << minSample << " maxSample: " << maxSample << endl;
mas01mc@17 2399 }
mas01mc@17 2400
mas01cr@133 2401 if(adbQueryResponse==0){
mas01cr@60 2402 if(verbosity>1) {
mas01mc@17 2403 cerr<<endl;
mas01cr@60 2404 }
mas01mc@17 2405 // Output answer
mas01mc@17 2406 // Loop over nearest neighbours
mas01mc@18 2407 for(k=0; k < min(trackNN,successfulTracks); k++)
mas01mc@18 2408 cout << fileTable+trackIDs[k]*O2_FILETABLESIZE << " " << trackDistances[k] << endl;
mas01mc@17 2409 }
mas01mc@17 2410 else{ // Process Web Services Query
mas01mc@18 2411 int listLen = min(trackNN, processedTracks);
mas01cr@133 2412 adbQueryResponse->result.__sizeRlist=listLen;
mas01cr@133 2413 adbQueryResponse->result.__sizeDist=listLen;
mas01cr@133 2414 adbQueryResponse->result.__sizeQpos=listLen;
mas01cr@133 2415 adbQueryResponse->result.__sizeSpos=listLen;
mas01cr@133 2416 adbQueryResponse->result.Rlist= new char*[listLen];
mas01cr@133 2417 adbQueryResponse->result.Dist = new double[listLen];
mas01cr@133 2418 adbQueryResponse->result.Qpos = new unsigned int[listLen];
mas01cr@133 2419 adbQueryResponse->result.Spos = new unsigned int[listLen];
mas01cr@133 2420 for(k=0; k<(unsigned)adbQueryResponse->result.__sizeRlist; k++){
mas01cr@133 2421 adbQueryResponse->result.Rlist[k]=new char[O2_MAXFILESTR];
mas01cr@133 2422 adbQueryResponse->result.Dist[k]=trackDistances[k];
mas01cr@133 2423 adbQueryResponse->result.Qpos[k]=trackQIndexes[k];
mas01cr@133 2424 adbQueryResponse->result.Spos[k]=trackSIndexes[k];
mas01cr@133 2425 sprintf(adbQueryResponse->result.Rlist[k], "%s", fileTable+trackIDs[k]*O2_FILETABLESIZE);
mas01mc@17 2426 }
mas01mc@17 2427 }
mas01mc@17 2428
mas01mc@17 2429 // Clean up
mas01mc@18 2430 if(trackOffsetTable)
mas01mc@18 2431 delete[] trackOffsetTable;
mas01mc@17 2432 if(queryCopy)
mas01mc@17 2433 delete[] queryCopy;
mas01cr@121 2434 if(qNorm)
mas01cr@121 2435 delete[] qNorm;
mas01cr@121 2436 if(sNorm)
mas01cr@121 2437 delete[] sNorm;
mas01cr@121 2438 if(sMeanL2)
mas01cr@121 2439 delete[] sMeanL2;
mas01mc@17 2440 if(D)
mas01mc@17 2441 delete[] D;
mas01mc@17 2442 if(DD)
mas01mc@17 2443 delete[] DD;
mas01mc@17 2444 if(timesdata)
mas01mc@17 2445 delete[] timesdata;
mas01mc@17 2446 if(meanDBdur)
mas01mc@17 2447 delete[] meanDBdur;
mas01mc@17 2448
mas01mc@17 2449
mas01mc@17 2450 }
mas01mc@17 2451
mas01cr@0 2452 // Unit norm block of features
mas01cr@0 2453 void audioDB::unitNorm(double* X, unsigned dim, unsigned n, double* qNorm){
mas01cr@0 2454 unsigned d;
mas01cr@59 2455 double L2, *p;
mas01cr@60 2456 if(verbosity>2) {
mas01cr@0 2457 cerr << "norming " << n << " vectors...";cerr.flush();
mas01cr@60 2458 }
mas01cr@0 2459 while(n--){
mas01cr@0 2460 p=X;
mas01cr@0 2461 L2=0.0;
mas01cr@0 2462 d=dim;
mas01cr@0 2463 while(d--){
mas01cr@0 2464 L2+=*p**p;
mas01cr@0 2465 p++;
mas01cr@0 2466 }
mas01mc@17 2467 /* L2=sqrt(L2);*/
mas01cr@0 2468 if(qNorm)
mas01cr@0 2469 *qNorm++=L2;
mas01mc@17 2470 /*
mas01cr@0 2471 oneOverL2 = 1.0/L2;
mas01cr@0 2472 d=dim;
mas01cr@0 2473 while(d--){
mas01cr@0 2474 *X*=oneOverL2;
mas01cr@0 2475 X++;
mas01mc@17 2476 */
mas01mc@17 2477 X+=dim;
mas01cr@0 2478 }
mas01cr@60 2479 if(verbosity>2) {
mas01cr@0 2480 cerr << "done..." << endl;
mas01cr@60 2481 }
mas01cr@0 2482 }
mas01cr@0 2483
mas01cr@0 2484 // Unit norm block of features
mas01cr@0 2485 void audioDB::unitNormAndInsertL2(double* X, unsigned dim, unsigned n, unsigned append=0){
mas01cr@0 2486 unsigned d;
mas01cr@59 2487 double *p;
mas01cr@0 2488 unsigned nn = n;
mas01cr@0 2489
mas01cr@0 2490 assert(l2normTable);
mas01cr@0 2491
mas01cr@0 2492 if( !append && (dbH->flags & O2_FLAG_L2NORM) )
mas01cr@0 2493 error("Database is already L2 normed", "automatic norm on insert is enabled");
mas01cr@0 2494
mas01cr@60 2495 if(verbosity>2) {
mas01cr@0 2496 cerr << "norming " << n << " vectors...";cerr.flush();
mas01cr@60 2497 }
mas01cr@0 2498
mas01cr@0 2499 double* l2buf = new double[n];
mas01cr@0 2500 double* l2ptr = l2buf;
mas01cr@0 2501 assert(l2buf);
mas01cr@0 2502 assert(X);
mas01cr@0 2503
mas01cr@0 2504 while(nn--){
mas01cr@0 2505 p=X;
mas01cr@0 2506 *l2ptr=0.0;
mas01cr@0 2507 d=dim;
mas01cr@0 2508 while(d--){
mas01cr@0 2509 *l2ptr+=*p**p;
mas01cr@0 2510 p++;
mas01cr@0 2511 }
mas01mc@17 2512 l2ptr++;
mas01mc@17 2513 /*
mas01mc@17 2514 oneOverL2 = 1.0/(*l2ptr++);
mas01mc@17 2515 d=dim;
mas01mc@17 2516 while(d--){
mas01cr@0 2517 *X*=oneOverL2;
mas01cr@0 2518 X++;
mas01mc@17 2519 }
mas01mc@17 2520 */
mas01mc@17 2521 X+=dim;
mas01cr@0 2522 }
mas01cr@0 2523 unsigned offset;
mas01cr@84 2524 if(append) {
mas01cr@84 2525 // FIXME: a hack, a very palpable hack: the vectors have already
mas01cr@84 2526 // been inserted, and dbH->length has already been updated. We
mas01cr@84 2527 // need to subtract off again the number of vectors that we've
mas01cr@84 2528 // inserted this time...
mas01cr@84 2529 offset=(dbH->length/(dbH->dim*sizeof(double)))-n; // number of vectors
mas01cr@84 2530 } else {
mas01cr@0 2531 offset=0;
mas01cr@84 2532 }
mas01cr@0 2533 memcpy(l2normTable+offset, l2buf, n*sizeof(double));
mas01cr@0 2534 if(l2buf)
mas01mc@17 2535 delete[] l2buf;
mas01cr@60 2536 if(verbosity>2) {
mas01cr@0 2537 cerr << "done..." << endl;
mas01cr@60 2538 }
mas01cr@0 2539 }
mas01cr@0 2540
mas01cr@0 2541
mas01cr@0 2542 // Start an audioDB server on the host
mas01cr@0 2543 void audioDB::startServer(){
mas01cr@0 2544 struct soap soap;
mas01cr@0 2545 int m, s; // master and slave sockets
mas01cr@0 2546 soap_init(&soap);
mas01cr@92 2547 // FIXME: largely this use of SO_REUSEADDR is to make writing (and
mas01cr@92 2548 // running) test cases more convenient, so that multiple test runs
mas01cr@92 2549 // in close succession don't fail because of a bin() error.
mas01cr@92 2550 // Investigate whether there are any potential drawbacks in this,
mas01cr@92 2551 // and also whether there's a better way to write the tests. --
mas01cr@92 2552 // CSR, 2007-10-03
mas01cr@92 2553 soap.bind_flags |= SO_REUSEADDR;
mas01cr@0 2554 m = soap_bind(&soap, NULL, port, 100);
mas01cr@0 2555 if (m < 0)
mas01cr@0 2556 soap_print_fault(&soap, stderr);
mas01cr@0 2557 else
mas01cr@0 2558 {
mas01cr@0 2559 fprintf(stderr, "Socket connection successful: master socket = %d\n", m);
mas01cr@0 2560 for (int i = 1; ; i++)
mas01cr@0 2561 {
mas01cr@0 2562 s = soap_accept(&soap);
mas01cr@0 2563 if (s < 0)
mas01cr@0 2564 {
mas01cr@0 2565 soap_print_fault(&soap, stderr);
mas01cr@0 2566 break;
mas01cr@0 2567 }
mas01cr@75 2568 fprintf(stderr, "%d: accepted connection from IP=%lu.%lu.%lu.%lu socket=%d\n", i,
mas01cr@0 2569 (soap.ip >> 24)&0xFF, (soap.ip >> 16)&0xFF, (soap.ip >> 8)&0xFF, soap.ip&0xFF, s);
mas01cr@0 2570 if (soap_serve(&soap) != SOAP_OK) // process RPC request
mas01cr@0 2571 soap_print_fault(&soap, stderr); // print error
mas01cr@0 2572 fprintf(stderr, "request served\n");
mas01cr@0 2573 soap_destroy(&soap); // clean up class instances
mas01cr@0 2574 soap_end(&soap); // clean up everything and close socket
mas01cr@0 2575 }
mas01cr@0 2576 }
mas01cr@0 2577 soap_done(&soap); // close master socket and detach environment
mas01cr@0 2578 }
mas01cr@0 2579
mas01cr@0 2580
mas01cr@0 2581 // web services
mas01cr@0 2582
mas01cr@0 2583 // SERVER SIDE
mas01cr@133 2584 int adb__status(struct soap* soap, xsd__string dbName, adb__statusResponse &adbStatusResponse){
mas01cr@21 2585 char* const argv[]={"audioDB",COM_STATUS,"-d",dbName};
mas01cr@21 2586 const unsigned argc = 4;
mas01cr@77 2587 try {
mas01cr@133 2588 audioDB(argc, argv, &adbStatusResponse);
mas01cr@77 2589 return SOAP_OK;
mas01cr@77 2590 } catch(char *err) {
mas01cr@77 2591 soap_receiver_fault(soap, err, "");
mas01cr@77 2592 return SOAP_FAULT;
mas01cr@77 2593 }
mas01cr@0 2594 }
mas01cr@0 2595
mas01cr@0 2596 // Literal translation of command line to web service
mas01cr@0 2597
mas01cr@133 2598 int adb__query(struct soap* soap, xsd__string dbName, xsd__string qKey, xsd__string keyList, xsd__string timesFileName, xsd__int qType, xsd__int qPos, xsd__int pointNN, xsd__int trackNN, xsd__int seqLen, adb__queryResponse &adbQueryResponse){
mas01cr@0 2599 char queryType[256];
mas01cr@0 2600 for(int k=0; k<256; k++)
mas01cr@0 2601 queryType[k]='\0';
mas01cr@105 2602 if(qType == O2_POINT_QUERY)
mas01cr@0 2603 strncpy(queryType, "point", strlen("point"));
mas01cr@105 2604 else if (qType == O2_SEQUENCE_QUERY)
mas01cr@0 2605 strncpy(queryType, "sequence", strlen("sequence"));
mas01cr@105 2606 else if(qType == O2_TRACK_QUERY)
mas01mc@18 2607 strncpy(queryType,"track", strlen("track"));
mas01cr@0 2608 else
mas01cr@0 2609 strncpy(queryType, "", strlen(""));
mas01cr@0 2610
mas01cr@0 2611 if(pointNN==0)
mas01cr@0 2612 pointNN=10;
mas01mc@18 2613 if(trackNN==0)
mas01mc@18 2614 trackNN=10;
mas01cr@0 2615 if(seqLen==0)
mas01cr@0 2616 seqLen=16;
mas01cr@0 2617
mas01cr@0 2618 char qPosStr[256];
mas01cr@0 2619 sprintf(qPosStr, "%d", qPos);
mas01cr@0 2620 char pointNNStr[256];
mas01cr@0 2621 sprintf(pointNNStr,"%d",pointNN);
mas01mc@18 2622 char trackNNStr[256];
mas01mc@18 2623 sprintf(trackNNStr,"%d",trackNN);
mas01cr@0 2624 char seqLenStr[256];
mas01cr@0 2625 sprintf(seqLenStr,"%d",seqLen);
mas01cr@0 2626
mas01cr@0 2627 const char* argv[] ={
mas01cr@0 2628 "./audioDB",
mas01cr@0 2629 COM_QUERY,
mas01cr@0 2630 queryType, // Need to pass a parameter
mas01cr@0 2631 COM_DATABASE,
mas01cr@166 2632 ENSURE_STRING(dbName),
mas01cr@0 2633 COM_FEATURES,
mas01cr@166 2634 ENSURE_STRING(qKey),
mas01cr@0 2635 COM_KEYLIST,
mas01cr@166 2636 ENSURE_STRING(keyList),
mas01cr@0 2637 COM_TIMES,
mas01cr@166 2638 ENSURE_STRING(timesFileName),
mas01cr@0 2639 COM_QPOINT,
mas01cr@0 2640 qPosStr,
mas01cr@0 2641 COM_POINTNN,
mas01cr@0 2642 pointNNStr,
mas01mc@18 2643 COM_TRACKNN,
mas01mc@18 2644 trackNNStr, // Need to pass a parameter
mas01cr@0 2645 COM_SEQLEN,
mas01cr@0 2646 seqLenStr
mas01cr@0 2647 };
mas01cr@0 2648
mas01cr@0 2649 const unsigned argc = 19;
mas01cr@79 2650 try {
mas01cr@133 2651 audioDB(argc, (char* const*)argv, &adbQueryResponse);
mas01cr@79 2652 return SOAP_OK;
mas01cr@79 2653 } catch (char *err) {
mas01cr@79 2654 soap_receiver_fault(soap, err, "");
mas01cr@79 2655 return SOAP_FAULT;
mas01cr@79 2656 }
mas01cr@0 2657 }
mas01cr@0 2658
mas01cr@0 2659 int main(const unsigned argc, char* const argv[]){
mas01cr@0 2660 audioDB(argc, argv);
mas01cr@0 2661 }
mas01cr@104 2662