annotate audioDB.cpp @ 400:8c7453fb5bd9 api-inversion

Invert audioDB::power_flag / audiodb_power() Here the exciting discovery is that the mmap(), memcpy(), munmap() sequence is in fact not safe. In principle an msync() call should be inserted before unmapping for in-core changes to mmap()ed files to be flushed to disk. In this case we work around the problem entirely, by not mmap()ing anything and doing everything with file descriptors. Amusingly, that's probably not desperately safe either, this time because we have to move the file descriptor position (which is also a shared resource). dup() doesn't save us, as the duplicate file descriptor shares a file position. This applies also to the filling of data_buffer in the query loop, and in fact basically any call to lseek(), which is why I'm not fixing it now. Solution: if you have multiple threads all acting at once on a single database, do one audiodb_open() per thread, for now at least.
author mas01cr
date Thu, 27 Nov 2008 16:22:52 +0000
parents a65b31660804
children a8a5f2ca5380
rev   line source
mas01cr@0 1 #include "audioDB.h"
mas01cr@385 2 extern "C" {
mas01cr@385 3 #include "audioDB_API.h"
mas01cr@385 4 }
mas01cr@0 5
mas01mc@308 6 LSH* SERVER_LSH_INDEX_SINGLETON;
mas01mc@324 7 char* SERVER_ADB_ROOT;
mas01mc@324 8 char* SERVER_ADB_FEATURE_ROOT;
mas01mc@308 9
mas01mc@292 10 PointPair::PointPair(Uns32T a, Uns32T b, Uns32T c):trackID(a),qpos(b),spos(c){};
mas01mc@292 11
mas01mc@292 12 bool operator<(const PointPair& a, const PointPair& b){
mas01mc@324 13 return ( (a.trackID<b.trackID) ||
mas01mc@324 14 ( (a.trackID==b.trackID) &&
mas01mc@324 15 ( (a.spos<b.spos) || ( (a.spos==b.spos) && (a.qpos < b.qpos) )) ) );
mas01mc@292 16 }
mas01mc@292 17
mas01mc@292 18 bool operator>(const PointPair& a, const PointPair& b){
mas01mc@324 19 return ( (a.trackID>b.trackID) ||
mas01mc@324 20 ( (a.trackID==b.trackID) &&
mas01mc@324 21 ( (a.spos>b.spos) || ( (a.spos==b.spos) && (a.qpos > b.qpos) )) ) );
mas01mc@292 22 }
mas01mc@292 23
mas01mc@292 24 bool operator==(const PointPair& a, const PointPair& b){
mas01mc@292 25 return ( (a.trackID==b.trackID) && (a.qpos==b.qpos) && (a.spos==b.spos) );
mas01mc@292 26 }
mas01mc@292 27
mas01cr@370 28 audioDB::audioDB(const unsigned argc, const char *argv[]): O2_AUDIODB_INITIALIZERS
mas01cr@76 29 {
mas01cr@0 30 if(processArgs(argc, argv)<0){
mas01cr@0 31 printf("No command found.\n");
mas01cr@0 32 cmdline_parser_print_version ();
mas01cr@0 33 if (strlen(gengetopt_args_info_purpose) > 0)
mas01cr@0 34 printf("%s\n", gengetopt_args_info_purpose);
mas01cr@0 35 printf("%s\n", gengetopt_args_info_usage);
mas01cr@0 36 printf("%s\n", gengetopt_args_info_help[1]);
mas01cr@0 37 printf("%s\n", gengetopt_args_info_help[2]);
mas01cr@0 38 printf("%s\n", gengetopt_args_info_help[0]);
mas01cr@151 39 error("No command found");
mas01cr@0 40 }
mas01cr@77 41
mas01mc@324 42 // Perform database prefix substitution
mas01mc@328 43 if(dbName && adb_root)
mas01mc@324 44 prefix_name((char** const)&dbName, adb_root);
mas01mc@324 45
mas01cr@0 46 if(O2_ACTION(COM_SERVER))
mas01cr@371 47 #ifdef LIBRARY
mas01cr@371 48 ;
mas01cr@371 49 #else
mas01cr@0 50 startServer();
mas01cr@371 51 #endif
mas01cr@0 52
mas01cr@0 53 else if(O2_ACTION(COM_CREATE))
mas01cr@0 54 create(dbName);
mas01cr@0 55
mas01cr@0 56 else if(O2_ACTION(COM_INSERT))
mas01cr@0 57 insert(dbName, inFile);
mas01cr@0 58
mas01cr@0 59 else if(O2_ACTION(COM_BATCHINSERT))
mas01cr@0 60 batchinsert(dbName, inFile);
mas01cr@0 61
mas01cr@0 62 else if(O2_ACTION(COM_QUERY))
mas01mc@307 63 if(isClient){
mas01cr@371 64 #ifdef LIBRARY
mas01cr@371 65 ;
mas01cr@371 66 #else
mas01mc@329 67 if(query_from_key){
mas01mc@332 68 VERB_LOG(1, "Calling web services query %s on database %s, query=%s\n", radius>0?"(Radius)":"(NN)", dbName, (key&&strlen(key))?key:inFile);
mas01mc@328 69 ws_query_by_key(dbName, key, inFile, (char*)hostport);
mas01mc@329 70 }
mas01mc@329 71 else{
mas01mc@332 72 VERB_LOG(1, "Calling web services query on database %s, query=%s\n", dbName, (key&&strlen(key))?key:inFile);
mas01mc@307 73 ws_query(dbName, inFile, (char*)hostport);
mas01mc@329 74 }
mas01cr@371 75 #endif
mas01mc@307 76 }
mas01cr@0 77 else
mas01cr@76 78 query(dbName, inFile);
mas01cr@0 79
mas01cr@0 80 else if(O2_ACTION(COM_STATUS))
mas01cr@0 81 if(isClient)
mas01cr@371 82 #ifdef LIBRARY
mas01cr@371 83 ;
mas01cr@371 84 #else
mas01cr@0 85 ws_status(dbName,(char*)hostport);
mas01cr@371 86 #endif
mas01cr@0 87 else
mas01cr@0 88 status(dbName);
mas01cr@280 89
mas01cr@280 90 else if(O2_ACTION(COM_SAMPLE))
mas01cr@280 91 sample(dbName);
mas01cr@0 92
mas01cr@0 93 else if(O2_ACTION(COM_L2NORM))
mas01cr@0 94 l2norm(dbName);
mas01cr@0 95
mas01cr@193 96 else if(O2_ACTION(COM_POWER))
mas01cr@193 97 power_flag(dbName);
mas01cr@193 98
mas01cr@0 99 else if(O2_ACTION(COM_DUMP))
mas01cr@0 100 dump(dbName);
mas01mc@292 101
mas01mc@334 102 else if(O2_ACTION(COM_LISZT))
mas01mc@334 103 if(isClient)
mas01cr@371 104 #ifdef LIBRARY
mas01cr@371 105 ;
mas01cr@371 106 #else
mas01mc@334 107 ws_liszt(dbName, (char*) hostport);
mas01cr@371 108 #endif
mas01mc@334 109 else
mas01mc@334 110 liszt(dbName, lisztOffset, lisztLength);
mas01mc@334 111
mas01mc@292 112 else if(O2_ACTION(COM_INDEX))
mas01mc@292 113 index_index_db(dbName);
mas01cr@0 114
mas01cr@0 115 else
mas01cr@0 116 error("Unrecognized command",command);
mas01cr@0 117 }
mas01cr@0 118
mas01cr@370 119 audioDB::audioDB(const unsigned argc, const char *argv[], adb__queryResponse *adbQueryResponse): O2_AUDIODB_INITIALIZERS
mas01cr@76 120 {
mas01cr@97 121 try {
mas01mc@338 122 isServer = 1; // Set to make errors report over SOAP
mas01cr@97 123 processArgs(argc, argv);
mas01mc@324 124 // Perform database prefix substitution
mas01mc@328 125 if(dbName && adb_root)
mas01mc@324 126 prefix_name((char** const)&dbName, adb_root);
mas01cr@97 127 assert(O2_ACTION(COM_QUERY));
mas01cr@133 128 query(dbName, inFile, adbQueryResponse);
mas01cr@97 129 } catch(char *err) {
mas01cr@97 130 cleanup();
mas01cr@97 131 throw(err);
mas01cr@97 132 }
mas01cr@76 133 }
mas01cr@76 134
mas01cr@370 135 audioDB::audioDB(const unsigned argc, const char *argv[], adb__statusResponse *adbStatusResponse): O2_AUDIODB_INITIALIZERS
mas01cr@76 136 {
mas01cr@97 137 try {
mas01mc@338 138 isServer = 1; // Set to make errors report over SOAP
mas01cr@97 139 processArgs(argc, argv);
mas01mc@324 140 // Perform database prefix substitution
mas01mc@328 141 if(dbName && adb_root)
mas01mc@324 142 prefix_name((char** const)&dbName, adb_root);
mas01cr@97 143 assert(O2_ACTION(COM_STATUS));
mas01cr@133 144 status(dbName, adbStatusResponse);
mas01cr@97 145 } catch(char *err) {
mas01cr@97 146 cleanup();
mas01cr@97 147 throw(err);
mas01cr@97 148 }
mas01cr@76 149 }
mas01cr@76 150
mas01cr@370 151 audioDB::audioDB(const unsigned argc, const char *argv[], adb__lisztResponse *adbLisztResponse): O2_AUDIODB_INITIALIZERS
mas01mc@334 152 {
mas01mc@334 153 try {
mas01mc@338 154 isServer = 1; // Set to make errors report over SOAP
mas01mc@338 155 processArgs(argc, argv);
mas01mc@334 156 // Perform database prefix substitution
mas01mc@334 157 if(dbName && adb_root)
mas01mc@334 158 prefix_name((char** const)&dbName, adb_root);
mas01mc@334 159 assert(O2_ACTION(COM_LISZT));
mas01mc@334 160 liszt(dbName, lisztOffset, lisztLength, adbLisztResponse);
mas01mc@334 161 } catch(char *err) {
mas01mc@334 162 cleanup();
mas01mc@334 163 throw(err);
mas01mc@334 164 }
mas01mc@334 165 }
mas01mc@334 166
mas01ik@355 167
mas01ik@355 168 //for the lib / API
mas01cr@395 169 audioDB::audioDB(const unsigned argc, const char *argv[], int * apierror, adb_t *a): O2_AUDIODB_INITIALIZERS
mas01ik@355 170 {
mas01ik@355 171
mas01ik@355 172 try {
mas01ik@355 173 UseApiError=1;
mas01cr@395 174 adb = a;
mas01ik@355 175
mas01ik@355 176 if(processArgs(argc, argv)<0){
mas01ik@355 177 printf("No command found.\n");
mas01ik@355 178 cmdline_parser_print_version ();
mas01ik@355 179 if (strlen(gengetopt_args_info_purpose) > 0)
mas01ik@355 180 printf("%s\n", gengetopt_args_info_purpose);
mas01ik@355 181 printf("%s\n", gengetopt_args_info_usage);
mas01ik@355 182 printf("%s\n", gengetopt_args_info_help[1]);
mas01ik@355 183 printf("%s\n", gengetopt_args_info_help[2]);
mas01ik@355 184 printf("%s\n", gengetopt_args_info_help[0]);
mas01ik@355 185 error("No command found");
mas01ik@355 186 }
mas01ik@355 187
mas01ik@355 188 adb__queryResponse adbq;
mas01ik@355 189
mas01ik@355 190 if(O2_ACTION(COM_CREATE))
mas01ik@355 191 create(dbName);
mas01ik@355 192
mas01ik@355 193 else if(O2_ACTION(COM_INSERT))
mas01ik@355 194 insert(dbName, inFile);
mas01ik@355 195
mas01ik@355 196 else if(O2_ACTION(COM_BATCHINSERT))
mas01ik@355 197 batchinsert(dbName, inFile);
mas01ik@355 198
mas01ik@355 199 else if(O2_ACTION(COM_QUERY))
mas01ik@355 200 if(isClient)
mas01ik@355 201 ;//ws_query(dbName, inFile, (char*)hostport);
mas01ik@355 202 else
mas01ik@355 203 query(dbName, inFile, &adbq);
mas01ik@355 204 //query(dbName, inFile);
mas01ik@355 205
mas01ik@355 206 else if(O2_ACTION(COM_STATUS))
mas01ik@355 207 if(isClient)
mas01ik@355 208 ;//ws_status(dbName,(char*)hostport);
mas01ik@355 209 else
mas01ik@355 210 status(dbName);
mas01ik@355 211
mas01ik@355 212 else if(O2_ACTION(COM_L2NORM))
mas01ik@355 213 l2norm(dbName);
mas01ik@355 214
mas01ik@355 215 else if(O2_ACTION(COM_POWER))
mas01ik@355 216 power_flag(dbName);
mas01ik@355 217
mas01ik@355 218 else if(O2_ACTION(COM_DUMP))
mas01ik@355 219 dump(dbName);
mas01ik@355 220
mas01ik@355 221 else
mas01ik@355 222 error("Unrecognized command",command);
mas01ik@355 223
mas01ik@355 224 } catch(int a) {
mas01ik@355 225 *apierror=a;
mas01ik@355 226 return;
mas01ik@355 227
mas01ik@355 228 }
mas01ik@355 229 *apierror=apierrortemp;
mas01ik@355 230 return;
mas01ik@355 231
mas01ik@355 232 }
mas01ik@355 233
mas01cr@395 234 //for API query
mas01cr@395 235 audioDB::audioDB(const unsigned argc, const char *argv[],adb__queryResponse *adbQueryResponse, int * apierror, adb_t *a): O2_AUDIODB_INITIALIZERS
mas01ik@355 236 {
mas01ik@355 237
mas01ik@355 238 try {
mas01ik@355 239 UseApiError=1;
mas01cr@395 240 adb = a;
mas01ik@355 241
mas01ik@355 242 if(processArgs(argc, argv)<0){
mas01ik@355 243 printf("No command found.\n");
mas01ik@355 244 cmdline_parser_print_version ();
mas01ik@355 245 if (strlen(gengetopt_args_info_purpose) > 0)
mas01ik@355 246 printf("%s\n", gengetopt_args_info_purpose);
mas01ik@355 247 printf("%s\n", gengetopt_args_info_usage);
mas01ik@355 248 printf("%s\n", gengetopt_args_info_help[1]);
mas01ik@355 249 printf("%s\n", gengetopt_args_info_help[2]);
mas01ik@355 250 printf("%s\n", gengetopt_args_info_help[0]);
mas01ik@355 251 error("No command found");
mas01ik@355 252 }
mas01ik@355 253
mas01ik@355 254 query(dbName, inFile, adbQueryResponse);
mas01ik@355 255
mas01ik@355 256 } catch(int a) {
mas01ik@355 257 *apierror=a;
mas01ik@355 258 return;
mas01ik@355 259
mas01ik@355 260 }
mas01ik@355 261 *apierror=apierrortemp;
mas01ik@355 262 return;
mas01ik@355 263
mas01ik@355 264 }
mas01ik@355 265
mas01cr@97 266 void audioDB::cleanup() {
mas01cr@122 267 cmdline_parser_free(&args_info);
mas01cr@0 268 if(indata)
mas01cr@0 269 munmap(indata,statbuf.st_size);
mas01cr@0 270 if(db)
mas01cr@196 271 munmap(db,getpagesize());
mas01cr@196 272 if(fileTable)
mas01cr@196 273 munmap(fileTable, fileTableLength);
mas01cr@196 274 if(trackTable)
mas01cr@196 275 munmap(trackTable, trackTableLength);
mas01cr@196 276 if(dataBuf)
mas01cr@196 277 munmap(dataBuf, dataBufLength);
mas01cr@196 278 if(timesTable)
mas01cr@196 279 munmap(timesTable, timesTableLength);
mas01mc@314 280 if(powerTable)
mas01mc@314 281 munmap(powerTable, powerTableLength);
mas01cr@196 282 if(l2normTable)
mas01cr@196 283 munmap(l2normTable, l2normTableLength);
mas01mc@324 284 if(featureFileNameTable)
mas01mc@324 285 munmap(featureFileNameTable, fileTableLength);
mas01mc@324 286 if(timesFileNameTable)
mas01mc@324 287 munmap(timesFileNameTable, fileTableLength);
mas01mc@324 288 if(powerFileNameTable)
mas01mc@324 289 munmap(powerFileNameTable, fileTableLength);
mas01mc@292 290 if(trackOffsetTable)
mas01ik@355 291 delete [] trackOffsetTable;
mas01mc@292 292 if(reporter)
mas01mc@292 293 delete reporter;
mas01mc@292 294 if(exact_evaluation_queue)
mas01mc@292 295 delete exact_evaluation_queue;
mas01cr@284 296 if(rng)
mas01cr@284 297 gsl_rng_free(rng);
mas01mc@292 298 if(vv)
mas01mc@292 299 delete vv;
mas01cr@0 300 if(infid>0)
mas01cr@0 301 close(infid);
mas01cr@395 302 if(adb && !UseApiError) {
mas01cr@392 303 audiodb_close(adb);
mas01cr@392 304 adb = NULL;
mas01cr@392 305 }
mas01mc@308 306 if(lsh!=SERVER_LSH_INDEX_SINGLETON)
mas01mc@308 307 delete lsh;
mas01cr@0 308 }
mas01cr@0 309
mas01cr@97 310 audioDB::~audioDB(){
mas01cr@97 311 cleanup();
mas01cr@97 312 }
mas01cr@97 313
mas01cr@370 314 int audioDB::processArgs(const unsigned argc, const char *argv[]){
mas01cr@0 315
mas01cr@0 316 if(argc<2){
mas01cr@0 317 cmdline_parser_print_version ();
mas01cr@0 318 if (strlen(gengetopt_args_info_purpose) > 0)
mas01cr@0 319 printf("%s\n", gengetopt_args_info_purpose);
mas01cr@0 320 printf("%s\n", gengetopt_args_info_usage);
mas01cr@0 321 printf("%s\n", gengetopt_args_info_help[1]);
mas01cr@0 322 printf("%s\n", gengetopt_args_info_help[2]);
mas01cr@0 323 printf("%s\n", gengetopt_args_info_help[0]);
mas01cr@0 324 exit(0);
mas01cr@0 325 }
mas01cr@0 326
mas01cr@345 327 /* KLUDGE: gengetopt generates a function which is not completely
mas01cr@345 328 const-clean in its declaration. We cast argv here to keep the
mas01cr@345 329 compiler happy. -- CSR, 2008-10-08 */
mas01cr@345 330 if (cmdline_parser (argc, (char *const *) argv, &args_info) != 0)
mas01cr@151 331 error("Error parsing command line");
mas01cr@0 332
mas01cr@0 333 if(args_info.help_given){
mas01cr@0 334 cmdline_parser_print_help();
mas01cr@0 335 exit(0);
mas01cr@0 336 }
mas01cr@0 337
mas01cr@0 338 if(args_info.verbosity_given){
mas01cr@239 339 verbosity = args_info.verbosity_arg;
mas01cr@239 340 if(verbosity < 0 || verbosity > 10){
mas01cr@239 341 std::cerr << "Warning: verbosity out of range, setting to 1" << std::endl;
mas01cr@239 342 verbosity = 1;
mas01cr@0 343 }
mas01cr@0 344 }
mas01cr@0 345
mas01cr@129 346 if(args_info.size_given) {
mas01cr@256 347 if(args_info.datasize_given) {
mas01cr@256 348 error("both --size and --datasize given", "");
mas01cr@256 349 }
mas01cr@256 350 if(args_info.ntracks_given) {
mas01cr@256 351 error("both --size and --ntracks given", "");
mas01cr@256 352 }
mas01cr@256 353 if(args_info.datadim_given) {
mas01cr@256 354 error("both --size and --datadim given", "");
mas01cr@256 355 }
mas01cr@196 356 if (args_info.size_arg < 50 || args_info.size_arg > 32000) {
mas01cr@129 357 error("Size out of range", "");
mas01cr@129 358 }
mas01cr@256 359 double ratio = (double) args_info.size_arg * 1000000 / ((double) O2_DEFAULTDBSIZE);
mas01cr@256 360 /* FIXME: what's the safe way of doing this? */
mas01cr@256 361 datasize = (unsigned int) ceil(datasize * ratio);
mas01cr@256 362 ntracks = (unsigned int) ceil(ntracks * ratio);
mas01cr@256 363 } else {
mas01cr@256 364 if(args_info.datasize_given) {
mas01cr@256 365 datasize = args_info.datasize_arg;
mas01cr@256 366 }
mas01cr@256 367 if(args_info.ntracks_given) {
mas01cr@256 368 ntracks = args_info.ntracks_arg;
mas01cr@256 369 }
mas01cr@256 370 if(args_info.datadim_given) {
mas01cr@256 371 datadim = args_info.datadim_arg;
mas01cr@256 372 }
mas01cr@129 373 }
mas01cr@129 374
mas01cr@239 375 if(args_info.radius_given) {
mas01cr@239 376 radius = args_info.radius_arg;
mas01mc@307 377 if(radius < 0 || radius > 1000000000) {
mas01cr@77 378 error("radius out of range");
mas01cr@239 379 } else {
mas01cr@239 380 VERB_LOG(3, "Setting radius to %f\n", radius);
mas01mc@17 381 }
mas01mc@17 382 }
mas01mc@17 383
mas01mc@292 384 sequenceLength = args_info.sequencelength_arg;
mas01mc@292 385 if(sequenceLength < 1 || sequenceLength > 1000) {
mas01mc@292 386 error("seqlen out of range: 1 <= seqlen <= 1000");
mas01mc@292 387 }
mas01mc@292 388 sequenceHop = args_info.sequencehop_arg;
mas01mc@292 389 if(sequenceHop < 1 || sequenceHop > 1000) {
mas01mc@292 390 error("seqhop out of range: 1 <= seqhop <= 1000");
mas01mc@292 391 }
mas01mc@292 392
mas01mc@292 393 if (args_info.absolute_threshold_given) {
mas01mc@292 394 if (args_info.absolute_threshold_arg >= 0) {
mas01mc@292 395 error("absolute threshold out of range: should be negative");
mas01mc@292 396 }
mas01mc@292 397 use_absolute_threshold = true;
mas01mc@292 398 absolute_threshold = args_info.absolute_threshold_arg;
mas01mc@292 399 }
mas01mc@292 400 if (args_info.relative_threshold_given) {
mas01mc@292 401 use_relative_threshold = true;
mas01mc@292 402 relative_threshold = args_info.relative_threshold_arg;
mas01mc@292 403 }
mas01mc@292 404
mas01mc@324 405 if (args_info.adb_root_given){
mas01mc@324 406 adb_root = args_info.adb_root_arg;
mas01mc@324 407 }
mas01mc@324 408
mas01mc@324 409 if (args_info.adb_feature_root_given){
mas01mc@324 410 adb_feature_root = args_info.adb_feature_root_arg;
mas01mc@324 411 }
mas01mc@324 412
mas01mc@324 413 // perform dbName path prefix SERVER-side subsitution
mas01mc@324 414 if(SERVER_ADB_ROOT && !adb_root)
mas01mc@324 415 adb_root = SERVER_ADB_ROOT;
mas01mc@324 416 if(SERVER_ADB_FEATURE_ROOT && !adb_feature_root)
mas01mc@324 417 adb_feature_root = SERVER_ADB_FEATURE_ROOT;
mas01mc@339 418
mas01cr@0 419 if(args_info.SERVER_given){
mas01cr@0 420 command=COM_SERVER;
mas01cr@0 421 port=args_info.SERVER_arg;
mas01cr@0 422 if(port<100 || port > 100000)
mas01cr@0 423 error("port out of range");
mas01cr@105 424 #if defined(O2_DEBUG)
mas01cr@104 425 struct sigaction sa;
mas01cr@104 426 sa.sa_sigaction = sigterm_action;
mas01cr@104 427 sa.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER;
mas01cr@104 428 sigaction(SIGTERM, &sa, NULL);
mas01cr@104 429 sa.sa_sigaction = sighup_action;
mas01cr@104 430 sa.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER;
mas01cr@104 431 sigaction(SIGHUP, &sa, NULL);
mas01cr@105 432 #endif
mas01mc@308 433 if(args_info.load_index_given){
mas01mc@308 434 if(!args_info.database_given)
mas01mc@308 435 error("load_index requires a --database argument");
mas01mc@308 436 else
mas01mc@308 437 dbName=args_info.database_arg;
mas01mc@308 438 if(!args_info.radius_given)
mas01mc@308 439 error("load_index requires a --radius argument");
mas01mc@308 440 if(!args_info.sequencelength_given)
mas01mc@308 441 error("load_index requires a --sequenceLength argument");
mas01mc@308 442 WS_load_index = true;
mas01mc@308 443 }
mas01cr@0 444 return 0;
mas01cr@0 445 }
mas01cr@0 446
mas01cr@0 447 // No return on client command, find database command
mas01cr@105 448 if(args_info.client_given){
mas01cr@105 449 command=COM_CLIENT;
mas01cr@105 450 hostport=args_info.client_arg;
mas01cr@105 451 isClient=1;
mas01cr@105 452 }
mas01cr@0 453
mas01cr@105 454 if(args_info.NEW_given){
mas01cr@105 455 command=COM_CREATE;
mas01cr@105 456 dbName=args_info.database_arg;
mas01cr@105 457 return 0;
mas01cr@105 458 }
mas01cr@0 459
mas01cr@105 460 if(args_info.STATUS_given){
mas01cr@105 461 command=COM_STATUS;
mas01cr@105 462 dbName=args_info.database_arg;
mas01cr@105 463 return 0;
mas01cr@105 464 }
mas01cr@0 465
mas01cr@280 466 if(args_info.SAMPLE_given) {
mas01cr@280 467 command = COM_SAMPLE;
mas01cr@280 468 dbName = args_info.database_arg;
mas01cr@280 469 sequenceLength = args_info.sequencelength_arg;
mas01cr@280 470 if(sequenceLength < 1 || sequenceLength > 1000) {
mas01cr@280 471 error("seqlen out of range: 1 <= seqlen <= 1000");
mas01cr@280 472 }
mas01cr@280 473 nsamples = args_info.nsamples_arg;
mas01cr@280 474 return 0;
mas01cr@280 475 }
mas01cr@280 476
mas01cr@105 477 if(args_info.DUMP_given){
mas01cr@105 478 command=COM_DUMP;
mas01cr@105 479 dbName=args_info.database_arg;
mas01cr@131 480 output = args_info.output_arg;
mas01cr@105 481 return 0;
mas01cr@105 482 }
mas01cr@0 483
mas01cr@105 484 if(args_info.L2NORM_given){
mas01cr@105 485 command=COM_L2NORM;
mas01cr@105 486 dbName=args_info.database_arg;
mas01cr@105 487 return 0;
mas01cr@105 488 }
mas01cr@0 489
mas01cr@193 490 if(args_info.POWER_given){
mas01cr@193 491 command=COM_POWER;
mas01cr@193 492 dbName=args_info.database_arg;
mas01cr@193 493 return 0;
mas01cr@193 494 }
mas01cr@193 495
mas01cr@370 496 if(args_info.INSERT_given) {
mas01cr@105 497 command=COM_INSERT;
mas01cr@105 498 dbName=args_info.database_arg;
mas01cr@105 499 inFile=args_info.features_arg;
mas01cr@370 500 if(args_info.key_given) {
mas01cr@370 501 if(!args_info.features_given) {
mas01mc@292 502 error("INSERT: '-k key' argument depends on '-f features'");
mas01cr@370 503 } else {
mas01mc@292 504 key=args_info.key_arg;
mas01cr@370 505 }
mas01cr@370 506 }
mas01cr@370 507 if(args_info.times_given) {
mas01cr@105 508 timesFileName=args_info.times_arg;
mas01cr@370 509 if(strlen(timesFileName)>0) {
mas01cr@370 510 if(!(timesFile = new std::ifstream(timesFileName,std::ios::in))) {
mas01cr@105 511 error("Could not open times file for reading", timesFileName);
mas01cr@370 512 }
mas01cr@105 513 usingTimes=1;
mas01cr@105 514 }
mas01cr@105 515 }
mas01cr@193 516 if (args_info.power_given) {
mas01cr@193 517 powerFileName = args_info.power_arg;
mas01cr@193 518 if (strlen(powerFileName) > 0) {
mas01cr@193 519 if (!(powerfd = open(powerFileName, O_RDONLY))) {
mas01cr@193 520 error("Could not open power file for reading", powerFileName, "open");
mas01cr@193 521 }
mas01cr@193 522 usingPower = 1;
mas01cr@193 523 }
mas01cr@193 524 }
mas01cr@105 525 return 0;
mas01cr@105 526 }
mas01cr@105 527
mas01cr@370 528 if(args_info.BATCHINSERT_given) {
mas01cr@105 529 command=COM_BATCHINSERT;
mas01cr@105 530 dbName=args_info.database_arg;
mas01cr@105 531 inFile=args_info.featureList_arg;
mas01cr@370 532 if(args_info.keyList_given) {
mas01cr@370 533 if(!args_info.featureList_given) {
mas01tc@300 534 error("BATCHINSERT: '-K keyList' argument depends on '-F featureList'");
mas01cr@370 535 } else {
mas01cr@304 536 key=args_info.keyList_arg; // INCONSISTENT NO CHECK
mas01cr@370 537 }
mas01cr@370 538 }
mas01cr@105 539 /* TO DO: REPLACE WITH
mas01cr@0 540 if(args_info.keyList_given){
mas01mc@18 541 trackFileName=args_info.keyList_arg;
mas01cr@239 542 if(strlen(trackFileName)>0 && !(trackFile = new std::ifstream(trackFileName,std::ios::in)))
mas01mc@18 543 error("Could not open keyList file for reading",trackFileName);
mas01cr@0 544 }
mas01cr@0 545 AND UPDATE BATCHINSERT()
mas01cr@105 546 */
mas01cr@105 547
mas01cr@370 548 if(args_info.timesList_given) {
mas01cr@105 549 timesFileName=args_info.timesList_arg;
mas01cr@370 550 if(strlen(timesFileName)>0) {
mas01cr@239 551 if(!(timesFile = new std::ifstream(timesFileName,std::ios::in)))
mas01cr@105 552 error("Could not open timesList file for reading", timesFileName);
mas01cr@105 553 usingTimes=1;
mas01cr@105 554 }
mas01cr@105 555 }
mas01cr@370 556 if(args_info.powerList_given) {
mas01cr@193 557 powerFileName=args_info.powerList_arg;
mas01cr@370 558 if(strlen(powerFileName)>0) {
mas01cr@239 559 if(!(powerFile = new std::ifstream(powerFileName,std::ios::in)))
mas01cr@193 560 error("Could not open powerList file for reading", powerFileName);
mas01cr@193 561 usingPower=1;
mas01cr@193 562 }
mas01cr@193 563 }
mas01cr@105 564 return 0;
mas01cr@105 565 }
mas01mc@292 566
mas01mc@292 567 // Set no_unit_norm flag
mas01mc@292 568 no_unit_norming = args_info.no_unit_norming_flag;
mas01mc@292 569 lsh_use_u_functions = args_info.lsh_use_u_functions_flag;
mas01mc@292 570
mas01mc@292 571 // LSH Index Command
mas01mc@292 572 if(args_info.INDEX_given){
mas01mc@292 573 if(radius <= 0 )
mas01mc@292 574 error("INDEXing requires a Radius argument");
mas01mc@292 575 if(!(sequenceLength>0 && sequenceLength <= O2_MAXSEQLEN))
mas01mc@292 576 error("INDEXing requires 1 <= sequenceLength <= 1000");
mas01mc@292 577 command=COM_INDEX;
mas01mc@337 578 if(!args_info.database_given)
mas01mc@337 579 error("INDEXing requires a database");
mas01mc@292 580 dbName=args_info.database_arg;
mas01mc@292 581
mas01mc@292 582 // Whether to store LSH hash tables for query in core (FORMAT2)
mas01mc@297 583 lsh_in_core = !args_info.lsh_on_disk_flag; // This flag is set to 0 if on_disk requested
mas01mc@292 584
mas01mc@292 585 lsh_param_w = args_info.lsh_w_arg;
mas01mc@292 586 if(!(lsh_param_w>0 && lsh_param_w<=O2_SERIAL_MAX_BINWIDTH))
mas01mc@292 587 error("Indexing parameter w out of range (0.0 < w <= 100.0)");
mas01mc@292 588
mas01mc@292 589 lsh_param_k = args_info.lsh_k_arg;
mas01mc@292 590 if(!(lsh_param_k>0 && lsh_param_k<=O2_SERIAL_MAX_FUNS))
mas01mc@292 591 error("Indexing parameter k out of range (1 <= k <= 100)");
mas01mc@292 592
mas01mc@292 593 lsh_param_m = args_info.lsh_m_arg;
mas01mc@292 594 if(!(lsh_param_m>0 && lsh_param_m<= (1 + (sqrt(1 + O2_SERIAL_MAX_TABLES*8.0)))/2.0))
mas01mc@292 595 error("Indexing parameter m out of range (1 <= m <= 20)");
mas01mc@292 596
mas01mc@292 597 lsh_param_N = args_info.lsh_N_arg;
mas01mc@292 598 if(!(lsh_param_N>0 && lsh_param_N<=O2_SERIAL_MAX_ROWS))
mas01mc@292 599 error("Indexing parameter N out of range (1 <= N <= 1000000)");
mas01mc@292 600
mas01mc@292 601 lsh_param_b = args_info.lsh_b_arg;
mas01mc@292 602 if(!(lsh_param_b>0 && lsh_param_b<=O2_SERIAL_MAX_TRACKBATCH))
mas01mc@292 603 error("Indexing parameter b out of range (1 <= b <= 10000)");
mas01mc@292 604
mas01mc@296 605 lsh_param_ncols = args_info.lsh_ncols_arg;
mas01mc@296 606 if(lsh_in_core) // We don't want to block rows with FORMAT2 indexing
mas01mc@296 607 lsh_param_ncols = O2_SERIAL_MAX_COLS;
mas01mc@292 608 if( !(lsh_param_ncols>0 && lsh_param_ncols<=O2_SERIAL_MAX_COLS))
mas01mc@292 609 error("Indexing parameter ncols out of range (1 <= ncols <= 1000");
mas01mc@292 610
mas01mc@292 611 return 0;
mas01mc@292 612 }
mas01mc@292 613
mas01cr@105 614 // Query command and arguments
mas01cr@105 615 if(args_info.QUERY_given){
mas01cr@105 616 command=COM_QUERY;
mas01cr@105 617 dbName=args_info.database_arg;
mas01mc@292 618 // XOR features and key search
mas01cr@370 619 if((!args_info.features_given && !args_info.key_given) || (args_info.features_given && args_info.key_given))
mas01mc@292 620 error("QUERY requires exactly one of either -f features or -k key");
mas01mc@292 621 if(args_info.features_given)
mas01mc@292 622 inFile=args_info.features_arg; // query from file
mas01mc@292 623 else{
mas01mc@292 624 query_from_key = true;
mas01mc@292 625 key=args_info.key_arg; // query from key
mas01mc@292 626 }
mas01mc@292 627
mas01cr@105 628 if(args_info.keyList_given){
mas01cr@105 629 trackFileName=args_info.keyList_arg;
mas01cr@239 630 if(strlen(trackFileName)>0 && !(trackFile = new std::ifstream(trackFileName,std::ios::in)))
mas01cr@105 631 error("Could not open keyList file for reading",trackFileName);
mas01cr@105 632 }
mas01cr@105 633
mas01cr@105 634 if(args_info.times_given){
mas01cr@105 635 timesFileName=args_info.times_arg;
mas01cr@105 636 if(strlen(timesFileName)>0){
mas01cr@239 637 if(!(timesFile = new std::ifstream(timesFileName,std::ios::in)))
mas01cr@105 638 error("Could not open times file for reading", timesFileName);
mas01cr@105 639 usingTimes=1;
mas01cr@105 640 }
mas01cr@105 641 }
mas01cr@193 642
mas01cr@193 643 if(args_info.power_given){
mas01cr@193 644 powerFileName=args_info.power_arg;
mas01cr@193 645 if(strlen(powerFileName)>0){
mas01cr@193 646 if (!(powerfd = open(powerFileName, O_RDONLY))) {
mas01cr@193 647 error("Could not open power file for reading", powerFileName, "open");
mas01cr@193 648 }
mas01cr@193 649 usingPower = 1;
mas01cr@193 650 }
mas01cr@193 651 }
mas01cr@105 652
mas01cr@105 653 // query type
mas01cr@105 654 if(strncmp(args_info.QUERY_arg, "track", MAXSTR)==0)
mas01cr@105 655 queryType=O2_TRACK_QUERY;
mas01cr@105 656 else if(strncmp(args_info.QUERY_arg, "point", MAXSTR)==0)
mas01cr@105 657 queryType=O2_POINT_QUERY;
mas01cr@105 658 else if(strncmp(args_info.QUERY_arg, "sequence", MAXSTR)==0)
mas01cr@105 659 queryType=O2_SEQUENCE_QUERY;
mas01mc@248 660 else if(strncmp(args_info.QUERY_arg, "nsequence", MAXSTR)==0)
mas01mc@248 661 queryType=O2_N_SEQUENCE_QUERY;
mas01mc@263 662 else if(strncmp(args_info.QUERY_arg, "onetoonensequence", MAXSTR)==0)
mas01mc@263 663 queryType=O2_ONE_TO_ONE_N_SEQUENCE_QUERY;
mas01cr@105 664 else
mas01cr@105 665 error("unsupported query type",args_info.QUERY_arg);
mas01cr@105 666
mas01cr@105 667 if(!args_info.exhaustive_flag){
mas01cr@105 668 queryPoint = args_info.qpoint_arg;
mas01cr@105 669 usingQueryPoint=1;
mas01cr@105 670 if(queryPoint<0 || queryPoint >10000)
mas01cr@105 671 error("queryPoint out of range: 0 <= queryPoint <= 10000");
mas01cr@105 672 }
mas01mc@292 673
mas01mc@296 674 // Whether to pre-load LSH hash tables for query (default on, if flag set then off)
mas01mc@297 675 lsh_in_core = !args_info.lsh_on_disk_flag;
mas01mc@292 676
mas01mc@292 677 // Whether to perform exact evaluation of points returned by LSH
mas01mc@292 678 lsh_exact = args_info.lsh_exact_flag;
mas01mc@292 679
mas01cr@105 680 pointNN = args_info.pointnn_arg;
mas01mc@263 681 if(pointNN < 1 || pointNN > O2_MAXNN) {
mas01mc@263 682 error("pointNN out of range: 1 <= pointNN <= 1000000");
mas01cr@105 683 }
mas01cr@105 684 trackNN = args_info.resultlength_arg;
mas01mc@263 685 if(trackNN < 1 || trackNN > O2_MAXNN) {
mas01mc@263 686 error("resultlength out of range: 1 <= resultlength <= 1000000");
mas01cr@105 687 }
mas01cr@105 688 return 0;
mas01cr@105 689 }
mas01mc@334 690
mas01mc@334 691 if(args_info.LISZT_given){
mas01mc@334 692 command = COM_LISZT;
mas01mc@334 693 dbName=args_info.database_arg;
mas01mc@334 694 lisztOffset = args_info.lisztOffset_arg;
mas01mc@334 695 lisztLength = args_info.lisztLength_arg;
mas01mc@334 696 if(args_info.lisztOffset_arg<0) // check upper bound later when database is opened
mas01mc@334 697 error("lisztOffset cannot be negative");
mas01mc@334 698 if(args_info.lisztLength_arg<0)
mas01mc@334 699 error("lisztLength cannot be negative");
mas01mc@334 700 if(lisztLength >1000000)
mas01mc@334 701 error("lisztLength too large (>1000000)");
mas01mc@334 702 return 0;
mas01mc@334 703 }
mas01mc@334 704
mas01cr@105 705 return -1; // no command found
mas01cr@0 706 }
mas01cr@0 707
mas01cr@133 708 void audioDB::status(const char* dbName, adb__statusResponse *adbStatusResponse){
mas01cr@395 709 adb_status_t status;
mas01cr@399 710 if(!adb) {
mas01cr@399 711 if(!(adb = audiodb_open(dbName, O_RDONLY))) {
mas01cr@399 712 error("Failed to open database file", dbName);
mas01cr@399 713 }
mas01cr@0 714 }
mas01cr@395 715 if(audiodb_status(adb, &status)) {
mas01cr@395 716 error("Failed to retrieve database status", dbName);
mas01cr@395 717 }
mas01cr@76 718
mas01cr@133 719 if(adbStatusResponse == 0) {
mas01cr@395 720 std::cout << "num files:" << status.numFiles << std::endl;
mas01cr@395 721 std::cout << "data dim:" << status.dim <<std::endl;
mas01cr@395 722 if(status.dim > 0) {
mas01cr@397 723 size_t bytes_per_vector = sizeof(double) * status.dim;
mas01cr@397 724 off_t nvectors = status.length / bytes_per_vector;
mas01cr@397 725 off_t data_region_vectors = status.data_region_size / bytes_per_vector;
mas01cr@395 726 std::cout << "total vectors:" << nvectors << std::endl;
mas01cr@395 727 std::cout << "vectors available:";
mas01cr@395 728 if(status.flags & O2_FLAG_LARGE_ADB) {
mas01cr@395 729 std::cout << O2_MAX_VECTORS - nvectors << std::endl;
mas01cr@395 730 } else {
mas01cr@395 731 std::cout << data_region_vectors - nvectors << std::endl;
mas01cr@395 732 }
mas01cr@76 733 }
mas01cr@395 734 if(!(status.flags & O2_FLAG_LARGE_ADB)) {
mas01cr@395 735 double used_frac = ((double) status.length) / status.data_region_size;
mas01cr@395 736 std::cout << "total bytes:" << status.length <<
mas01cr@395 737 " (" << (100.0*used_frac) << "%)" << std::endl;
mas01cr@395 738 std::cout << "bytes available:" << status.data_region_size - status.length <<
mas01cr@395 739 " (" << (100.0*(1-used_frac)) << "%)" << std::endl;
mas01mc@324 740 }
mas01cr@395 741 std::cout << "flags:" << " l2norm[" << DISPLAY_FLAG(status.flags&O2_FLAG_L2NORM)
mas01cr@395 742 << "] minmax[" << DISPLAY_FLAG(status.flags&O2_FLAG_MINMAX)
mas01cr@395 743 << "] power[" << DISPLAY_FLAG(status.flags&O2_FLAG_POWER)
mas01cr@395 744 << "] times[" << DISPLAY_FLAG(status.flags&O2_FLAG_TIMES)
mas01cr@395 745 << "] largeADB[" << DISPLAY_FLAG(status.flags&O2_FLAG_LARGE_ADB)
mas01mc@324 746 << "]" << endl;
mas01mc@324 747
mas01cr@395 748 std::cout << "null count: " << status.nullCount << " small sequence count " << status.dudCount-status.nullCount << std::endl;
mas01cr@76 749 } else {
mas01cr@395 750 adbStatusResponse->result.numFiles = status.numFiles;
mas01cr@395 751 adbStatusResponse->result.dim = status.dim;
mas01cr@395 752 adbStatusResponse->result.length = status.length;
mas01cr@395 753 adbStatusResponse->result.dudCount = status.dudCount;
mas01cr@395 754 adbStatusResponse->result.nullCount = status.nullCount;
mas01cr@395 755 adbStatusResponse->result.flags = status.flags;
mas01cr@76 756 }
mas01cr@0 757 }
mas01cr@0 758
mas01cr@196 759 void audioDB::l2norm(const char* dbName) {
mas01cr@196 760 forWrite = true;
mas01cr@196 761 initTables(dbName, 0);
mas01mc@324 762 if( !(dbH->flags & O2_FLAG_LARGE_ADB ) && (dbH->length>0) ){
mas01cr@196 763 /* FIXME: should probably be uint64_t */
mas01cr@0 764 unsigned numVectors = dbH->length/(sizeof(double)*dbH->dim);
mas01cr@196 765 CHECKED_MMAP(double *, dataBuf, dbH->dataOffset, dataBufLength);
mas01cr@0 766 unitNormAndInsertL2(dataBuf, dbH->dim, numVectors, 0); // No append
mas01cr@0 767 }
mas01cr@0 768 // Update database flags
mas01cr@0 769 dbH->flags = dbH->flags|O2_FLAG_L2NORM;
mas01cr@0 770 memcpy (db, dbH, O2_HEADERSIZE);
mas01cr@0 771 }
mas01cr@193 772
mas01cr@193 773 void audioDB::power_flag(const char *dbName) {
mas01cr@400 774 if(!adb) {
mas01cr@400 775 if(!(adb = audiodb_open(dbName, O_RDWR))) {
mas01cr@400 776 error("Failed to open database file", dbName);
mas01cr@400 777 }
mas01cr@193 778 }
mas01cr@400 779 if(audiodb_power(adb)) {
mas01cr@400 780 error("can't turn on power flag for database", dbName);
mas01cr@400 781 }
mas01cr@193 782 }
mas01cr@193 783
mas01cr@385 784 void audioDB::create(const char *dbName) {
mas01cr@399 785 if(adb) {
mas01cr@399 786 error("Already have an adb in this object", "");
mas01cr@399 787 }
mas01cr@391 788 if(!(adb = audiodb_create(dbName, datasize, ntracks, datadim))) {
mas01cr@392 789 error("Failed to create database file", dbName);
mas01cr@385 790 }
mas01cr@385 791 }
mas01cr@385 792
mas01cr@399 793 void audioDB::dump(const char *dbName) {
mas01cr@399 794 if(!adb) {
mas01cr@399 795 if(!(adb = audiodb_open(dbName, O_RDONLY))) {
mas01cr@399 796 error("Failed to open database file", dbName);
mas01cr@399 797 }
mas01cr@399 798 }
mas01cr@399 799 if(audiodb_dump(adb, output)) {
mas01cr@399 800 error("Failed to dump database to ", output);
mas01cr@399 801 }
mas01cr@399 802 status(dbName);
mas01cr@399 803 }
mas01cr@239 804 // Unit norm block of features
mas01cr@0 805
mas01cr@239 806 /* FIXME: in fact this does not unit norm a block of features, it just
mas01cr@239 807 records the L2 norms somewhere. unitNorm() does in fact unit norm
mas01cr@239 808 a block of features. */
mas01cr@0 809 void audioDB::unitNormAndInsertL2(double* X, unsigned dim, unsigned n, unsigned append=0){
mas01cr@0 810 unsigned d;
mas01cr@59 811 double *p;
mas01cr@0 812 unsigned nn = n;
mas01cr@0 813
mas01cr@0 814 assert(l2normTable);
mas01cr@0 815
mas01mc@324 816 if( !(dbH->flags & O2_FLAG_LARGE_ADB) && !append && (dbH->flags & O2_FLAG_L2NORM) )
mas01cr@0 817 error("Database is already L2 normed", "automatic norm on insert is enabled");
mas01cr@0 818
mas01cr@239 819 VERB_LOG(2, "norming %u vectors...", n);
mas01cr@0 820
mas01cr@0 821 double* l2buf = new double[n];
mas01cr@0 822 double* l2ptr = l2buf;
mas01cr@0 823 assert(l2buf);
mas01cr@0 824 assert(X);
mas01cr@0 825
mas01cr@0 826 while(nn--){
mas01cr@0 827 p=X;
mas01cr@0 828 *l2ptr=0.0;
mas01cr@0 829 d=dim;
mas01cr@0 830 while(d--){
mas01cr@0 831 *l2ptr+=*p**p;
mas01cr@0 832 p++;
mas01cr@0 833 }
mas01mc@17 834 l2ptr++;
mas01mc@17 835 X+=dim;
mas01cr@0 836 }
mas01cr@0 837 unsigned offset;
mas01cr@84 838 if(append) {
mas01cr@84 839 // FIXME: a hack, a very palpable hack: the vectors have already
mas01cr@84 840 // been inserted, and dbH->length has already been updated. We
mas01cr@84 841 // need to subtract off again the number of vectors that we've
mas01cr@84 842 // inserted this time...
mas01cr@84 843 offset=(dbH->length/(dbH->dim*sizeof(double)))-n; // number of vectors
mas01cr@84 844 } else {
mas01cr@0 845 offset=0;
mas01cr@84 846 }
mas01cr@0 847 memcpy(l2normTable+offset, l2buf, n*sizeof(double));
mas01cr@0 848 if(l2buf)
mas01mc@17 849 delete[] l2buf;
mas01cr@239 850 VERB_LOG(2, " done.");
mas01cr@193 851 }
mas01cr@193 852
mas01mc@308 853 // This entry point is visited once per instance
mas01mc@308 854 // so it is a good place to set any global state variables
mas01cr@370 855 int main(const int argc, const char* argv[]){
mas01mc@308 856 SERVER_LSH_INDEX_SINGLETON = 0; // Initialize global variables
mas01mc@324 857 SERVER_ADB_ROOT = 0; // Server-side database root prefix
mas01mc@324 858 SERVER_ADB_FEATURE_ROOT = 0; // Server-side features root prefix
mas01cr@0 859 audioDB(argc, argv);
mas01cr@0 860 }
mas01ik@355 861
mas01ik@355 862
mas01ik@355 863 extern "C" {
mas01ik@355 864
mas01ik@355 865 /* for API questions contact
mas01ik@355 866 * Christophe Rhodes c.rhodes@gold.ac.uk
mas01ik@355 867 * Ian Knopke mas01ik@gold.ac.uk, ian.knopke@gmail.com */
mas01ik@355 868
mas01ik@355 869 int audiodb_insert(adb_ptr mydb, adb_insert_ptr ins) {
mas01cr@370 870 const char *argv[15];
mas01ik@355 871 int argvctr=0;
mas01ik@355 872 int apierror=0;
mas01ik@355 873
mas01ik@355 874 argv[argvctr++]="audioDB";
mas01ik@355 875 argv[argvctr++]="-I";
mas01ik@355 876 argv[argvctr++]="-d";
mas01cr@388 877 argv[argvctr++]=mydb->path;
mas01ik@355 878 argv[argvctr++]="-f";
mas01ik@355 879 argv[argvctr++]=ins->features;
mas01ik@355 880
mas01ik@355 881 if (ins->times){
mas01ik@355 882 argv[argvctr++]="--times";
mas01ik@355 883 argv[argvctr++]=ins->times;
mas01ik@355 884 }
mas01ik@355 885
mas01ik@355 886 if (ins->power){
mas01ik@355 887 argv[argvctr++]="-w";
mas01ik@355 888 argv[argvctr++]=ins->power;
mas01ik@355 889 }
mas01ik@355 890
mas01ik@355 891 if (ins->key){
mas01ik@355 892 argv[argvctr++]="--key";
mas01ik@355 893 argv[argvctr++]=ins->key;
mas01ik@355 894 }
mas01cr@382 895 argv[argvctr]='\0';
mas01ik@355 896
mas01cr@395 897 audioDB::audioDB(argvctr,argv,&apierror,mydb);
mas01ik@355 898 return apierror;
mas01ik@355 899 }
mas01ik@355 900
mas01ik@355 901
mas01ik@355 902 int audiodb_batchinsert(adb_ptr mydb, adb_insert_ptr ins, unsigned int size) {
mas01ik@355 903
mas01cr@370 904 const char *argv[22];
mas01ik@355 905 int argvctr=0;
mas01ik@355 906 unsigned int i=0;
mas01ik@355 907 char tempfeaturename[]="tempfeatureXXXXXX";
mas01ik@355 908 char temppowername[]="temppowerXXXXXX";
mas01ik@355 909 char tempkeyname[]="tempkeyXXXXXX";
mas01ik@355 910 char temptimesname[]="temptimesXXXXXX";
mas01cr@370 911 int tempfeaturefd = -1;
mas01cr@370 912 int temppowerfd = -1;
mas01cr@370 913 int tempkeyfd = -1;
mas01cr@370 914 int temptimesfd = -1;
mas01ik@355 915
mas01ik@355 916 int flags[4]={0};
mas01ik@355 917 int apierror=0;
mas01ik@355 918
mas01ik@355 919 /* So the final API should take an array of structs. However, the current
mas01ik@355 920 * version requires four separate text files. So temporarily, we need to
mas01ik@355 921 * unpack the struct array, make four separate text files, and then reinsert
mas01ik@355 922 * them into the command-line call. This should change as soon as possible */
mas01ik@355 923
mas01ik@355 924
mas01ik@355 925 argv[argvctr++]="audioDB";
mas01ik@355 926 argv[argvctr++]="-B";
mas01ik@355 927 argv[argvctr++]="-d";
mas01cr@388 928 argv[argvctr++]=mydb->path;
mas01ik@355 929
mas01ik@355 930
mas01ik@355 931 /* assume struct is well formed for all entries */
mas01ik@355 932 if (ins[0].features){ flags[0]++;} else {
mas01ik@355 933 /* short circuit the case where there are no features in the structs */
mas01ik@355 934 return -1;
mas01ik@355 935 } ;
mas01ik@355 936 if (ins[0].power){ flags[1]++;};
mas01ik@355 937 if (ins[0].key){ flags[2]++;};
mas01ik@355 938 if (ins[0].times){ flags[3]++;};
mas01ik@355 939
mas01ik@355 940
mas01ik@355 941 /* make four temp files */
mas01cr@370 942 if ((tempfeaturefd = mkstemp(tempfeaturename)) == -1)
mas01cr@370 943 goto error;
mas01cr@370 944 if ((temppowerfd = mkstemp(temppowername)) == -1)
mas01cr@370 945 goto error;
mas01cr@370 946 if ((tempkeyfd=mkstemp(tempkeyname)) == -1)
mas01cr@370 947 goto error;
mas01cr@370 948 if ((temptimesfd=mkstemp(temptimesname)) == -1)
mas01cr@370 949 goto error;
mas01ik@355 950
mas01ik@355 951 /* Ok, so we should have a working set of files to write to */
mas01ik@355 952 /* I'm going to assume that the same format is kept for all structs in the array */
mas01ik@355 953 /* That is, each struct should be correctly formed, and contain at least a features file, because I'm just going to pass the terms along to the text files */
mas01cr@370 954 for (i = 0; i < size; i++) {
mas01cr@370 955 if (write(tempfeaturefd,ins[i].features,strlen(ins[i].features)) != (ssize_t) strlen(ins[i].features))
mas01cr@370 956 goto error;
mas01cr@370 957 if (write(tempfeaturefd,"\n",1) != 1)
mas01cr@370 958 goto error;
mas01ik@355 959
mas01cr@370 960 if (flags[1]) {
mas01cr@370 961 if (write(temppowerfd,ins[i].power,strlen(ins[i].power)) != (ssize_t) strlen(ins[i].power))
mas01cr@370 962 goto error;
mas01cr@370 963 if (write(temppowerfd,"\n",1) != 1)
mas01cr@370 964 goto error;
mas01cr@370 965 }
mas01cr@370 966 if (flags[2]) {
mas01cr@370 967 if (write(tempkeyfd,ins[i].key,strlen(ins[i].key)) != (ssize_t) strlen(ins[i].key))
mas01cr@370 968 goto error;
mas01cr@370 969 if (write(tempkeyfd,"\n",1) != 1)
mas01cr@370 970 goto error;
mas01cr@370 971 }
mas01cr@370 972 if (flags[3]) {
mas01cr@370 973 if (write(temptimesfd,ins[i].times,strlen(ins[i].times)) != (ssize_t) strlen(ins[i].times))
mas01cr@370 974 goto error;
mas01cr@370 975 if (write(temptimesfd,"\n",1) != 1)
mas01cr@370 976 goto error;
mas01cr@370 977 }
mas01cr@370 978 }
mas01ik@355 979
mas01ik@355 980 argv[argvctr++]="-F";
mas01ik@355 981 argv[argvctr++]=tempfeaturename;
mas01ik@355 982 close(tempfeaturefd);
mas01ik@355 983 close(temppowerfd);
mas01ik@355 984 close(tempkeyfd);
mas01ik@355 985 close(temptimesfd);
mas01ik@355 986
mas01ik@355 987 if (flags[1]){
mas01ik@355 988 argv[argvctr++]="--powerList";
mas01ik@355 989 argv[argvctr++]=temppowername;
mas01ik@355 990 }
mas01ik@355 991
mas01ik@355 992 if (flags[2]){
mas01ik@355 993 argv[argvctr++]="--keyList";
mas01ik@355 994 argv[argvctr++]=tempkeyname;
mas01ik@355 995 }
mas01ik@355 996
mas01ik@355 997 if (flags[3]){
mas01ik@355 998 argv[argvctr++]="--timesList";
mas01ik@355 999 argv[argvctr++]=temptimesname;
mas01ik@355 1000 }
mas01ik@355 1001
mas01cr@382 1002 argv[argvctr]='\0';
mas01ik@355 1003
mas01cr@395 1004 audioDB::audioDB(argvctr,argv,&apierror,mydb);
mas01ik@355 1005
mas01ik@355 1006 remove(tempfeaturename);
mas01ik@355 1007 remove(temppowername);
mas01ik@355 1008 remove(tempkeyname);
mas01ik@355 1009 remove(temptimesname);
mas01ik@355 1010
mas01ik@355 1011
mas01ik@355 1012 return apierror;
mas01cr@370 1013
mas01cr@370 1014 error:
mas01cr@370 1015 if(tempfeaturefd != -1) {
mas01cr@370 1016 close(tempfeaturefd);
mas01cr@370 1017 remove(tempfeaturename);
mas01cr@370 1018 }
mas01cr@370 1019 if(temppowerfd != -1) {
mas01cr@370 1020 close(temppowerfd);
mas01cr@370 1021 remove(temppowername);
mas01cr@370 1022 }
mas01cr@370 1023 if(tempkeyfd != -1) {
mas01cr@370 1024 close(tempkeyfd);
mas01cr@370 1025 remove(tempkeyname);
mas01cr@370 1026 }
mas01cr@370 1027 if(temptimesfd != -1) {
mas01cr@370 1028 close(temptimesfd);
mas01cr@370 1029 remove(temptimesname);
mas01cr@370 1030 }
mas01cr@370 1031 return -1;
mas01ik@355 1032 }
mas01ik@355 1033
mas01ik@355 1034
mas01ik@355 1035 int audiodb_query(adb_ptr mydb, adb_query_ptr adbq, adb_queryresult_ptr adbqr){
mas01ik@355 1036
mas01cr@370 1037 const char *argv[32];
mas01ik@355 1038 int argvctr=0;
mas01ik@355 1039 char tempstr1[200];
mas01ik@355 1040 char tempstr2[200];
mas01ik@355 1041 char tempstr3[200];
mas01ik@355 1042 int apierror=0;
mas01ik@355 1043
mas01ik@355 1044 adb__queryResponse adbQueryResponse;
mas01ik@355 1045
mas01ik@355 1046 /* TODO: may need error checking here */
mas01ik@355 1047 /* currently counting on audioDB binary to fail for me */
mas01ik@355 1048 argv[argvctr++]="audioDB";
mas01ik@355 1049
mas01ik@355 1050 if(adbq->querytype){
mas01ik@355 1051 argv[argvctr++]="-Q";
mas01ik@355 1052 argv[argvctr++]=adbq->querytype;
mas01ik@355 1053 }
mas01ik@355 1054
mas01cr@388 1055 if(mydb->path){
mas01ik@355 1056 argv[argvctr++]="-d";
mas01cr@388 1057 argv[argvctr++]=mydb->path;
mas01ik@355 1058 }
mas01ik@355 1059
mas01ik@355 1060 if (adbq->feature){
mas01ik@355 1061 argv[argvctr++]="-f";
mas01ik@355 1062 argv[argvctr++]=adbq->feature;
mas01ik@355 1063 }
mas01ik@355 1064
mas01ik@355 1065 if (adbq->power){
mas01ik@355 1066 argv[argvctr++]="-w";
mas01ik@355 1067 argv[argvctr++]=adbq->power;
mas01ik@355 1068 }
mas01ik@355 1069
mas01ik@355 1070 if (adbq->qpoint){
mas01ik@355 1071 argv[argvctr++]="-p";
mas01ik@355 1072 argv[argvctr++]=adbq->qpoint;
mas01ik@355 1073 }
mas01ik@355 1074 if (adbq->numpoints){
mas01ik@355 1075 argv[argvctr++]="-n";
mas01ik@355 1076 argv[argvctr++]=adbq->numpoints;
mas01ik@355 1077 }
mas01ik@355 1078 if (adbq->radius){
mas01ik@355 1079 argv[argvctr++]="-R";
mas01ik@355 1080 argv[argvctr++]=adbq->radius;
mas01ik@355 1081 }
mas01ik@355 1082 if(adbq->resultlength){
mas01ik@355 1083 argv[argvctr++]="-r";
mas01ik@355 1084 argv[argvctr++]=adbq->resultlength;
mas01ik@355 1085 }
mas01ik@355 1086 if(adbq->sequencelength){
mas01ik@355 1087 argv[argvctr++]="-l";
mas01ik@355 1088 argv[argvctr++]=adbq->sequencelength;
mas01ik@355 1089 }
mas01ik@355 1090 if(adbq->sequencehop){
mas01ik@355 1091 argv[argvctr++]="-h";
mas01ik@355 1092 argv[argvctr++]=adbq->sequencehop;
mas01ik@355 1093 }
mas01ik@355 1094
mas01ik@355 1095 if (adbq->absolute_threshold){
mas01ik@355 1096 argv[argvctr++]="--absolute-threshold";
mas01ik@355 1097 snprintf(tempstr1,sizeof(tempstr1),"%f",adbq->absolute_threshold);
mas01ik@355 1098 argv[argvctr++]=tempstr1;
mas01ik@355 1099 }
mas01ik@355 1100
mas01ik@355 1101 if (adbq->relative_threshold){
mas01ik@355 1102 argv[argvctr++]="--relative-threshold";
mas01ik@355 1103 snprintf(tempstr2,sizeof(tempstr2),"%f",adbq->relative_threshold);
mas01ik@355 1104 argv[argvctr++]=tempstr2;
mas01ik@355 1105 }
mas01ik@355 1106
mas01ik@355 1107 if (adbq->exhaustive){
mas01ik@355 1108 argv[argvctr++]="--exhaustive";
mas01ik@355 1109 }
mas01ik@355 1110
mas01ik@355 1111 if (adbq->expandfactor){
mas01ik@355 1112 argv[argvctr++]="--expandfactor";
mas01ik@355 1113 snprintf(tempstr3,sizeof(tempstr3),"%f",adbq->expandfactor);
mas01ik@355 1114 argv[argvctr++]=tempstr3;
mas01ik@355 1115 }
mas01ik@355 1116
mas01ik@355 1117 if (adbq->rotate){
mas01ik@355 1118 argv[argvctr++]="--rotate";
mas01ik@355 1119 }
mas01ik@355 1120
mas01ik@355 1121 if (adbq->keylist){
mas01ik@355 1122 argv[argvctr++]="-K";
mas01ik@355 1123 argv[argvctr++]=adbq->keylist;
mas01ik@355 1124 }
mas01cr@382 1125 argv[argvctr]='\0';
mas01ik@355 1126
mas01ik@355 1127 /* debugging */
mas01ik@355 1128
mas01cr@395 1129 audioDB::audioDB(argvctr,argv, &adbQueryResponse, &apierror,mydb);
mas01ik@355 1130
mas01ik@355 1131 //copy data over here from adbQueryResponse to adbqr
mas01ik@355 1132 adbqr->sizeRlist=adbQueryResponse.result.__sizeRlist;
mas01ik@355 1133 adbqr->sizeDist=adbQueryResponse.result.__sizeDist;
mas01ik@355 1134 adbqr->sizeQpos=adbQueryResponse.result.__sizeQpos;
mas01ik@355 1135 adbqr->sizeSpos=adbQueryResponse.result.__sizeSpos;
mas01ik@355 1136 adbqr->Rlist=adbQueryResponse.result.Rlist;
mas01ik@355 1137 adbqr->Dist=adbQueryResponse.result.Dist;
mas01ik@355 1138 adbqr->Qpos=adbQueryResponse.result.Qpos;
mas01ik@355 1139 adbqr->Spos=adbQueryResponse.result.Spos;
mas01ik@355 1140
mas01ik@355 1141 return apierror;
mas01ik@355 1142 }
mas01ik@355 1143
mas01ik@355 1144 int audiodb_l2norm(adb_ptr mydb){
mas01ik@355 1145
mas01cr@370 1146 const char *argv[5];
mas01ik@355 1147 int apierror=0;
mas01ik@355 1148
mas01ik@355 1149 argv[0]="audioDB";
mas01ik@355 1150 argv[1]="--L2NORM";
mas01ik@355 1151 argv[2]="-d";
mas01cr@388 1152 argv[3]=mydb->path;
mas01ik@355 1153 argv[4]='\0';
mas01ik@355 1154
mas01cr@395 1155 audioDB::audioDB(4,argv,&apierror,mydb);
mas01ik@355 1156 return apierror;
mas01ik@355 1157 }
mas01ik@355 1158 }
mas01ik@355 1159