comparison audioDB.cpp @ 498:342822c2d49a

Merge api-inversion branch (-r656:771, but I don't expect to return to that branch) into the trunk. I expect there to be minor performance regressions (e.g. in the SOAP server index cacheing, which I have forcibly removed) and minor unplugged memory leaks (e.g. in audioDB::query(), where I don't free up the datum). I hope that these leaks and performance regressions can be plugged in short order. I also expect that some (but maybe not all) of the issues currently addressed in the memory-leaks branch are superseded or fixed by this merge. There remains much work to be done; go forth and do it.
author mas01cr
date Sat, 10 Jan 2009 16:47:57 +0000
parents f9d86b1db21c
children da4b76190d43
comparison
equal deleted inserted replaced
476:a7193678280b 498:342822c2d49a
1 #include "audioDB.h" 1 #include "audioDB.h"
2 2 extern "C" {
3 LSH* SERVER_LSH_INDEX_SINGLETON; 3 #include "audioDB_API.h"
4 #include "audioDB-internals.h"
5 }
6 #include "reporter.h"
7
4 char* SERVER_ADB_ROOT; 8 char* SERVER_ADB_ROOT;
5 char* SERVER_ADB_FEATURE_ROOT; 9 char* SERVER_ADB_FEATURE_ROOT;
6
7 PointPair::PointPair(Uns32T a, Uns32T b, Uns32T c):trackID(a),qpos(b),spos(c){};
8
9 bool operator<(const PointPair& a, const PointPair& b){
10 return ( (a.trackID<b.trackID) ||
11 ( (a.trackID==b.trackID) &&
12 ( (a.spos<b.spos) || ( (a.spos==b.spos) && (a.qpos < b.qpos) )) ) );
13 }
14
15 bool operator>(const PointPair& a, const PointPair& b){
16 return ( (a.trackID>b.trackID) ||
17 ( (a.trackID==b.trackID) &&
18 ( (a.spos>b.spos) || ( (a.spos==b.spos) && (a.qpos > b.qpos) )) ) );
19 }
20
21 bool operator==(const PointPair& a, const PointPair& b){
22 return ( (a.trackID==b.trackID) && (a.qpos==b.qpos) && (a.spos==b.spos) );
23 }
24 10
25 audioDB::audioDB(const unsigned argc, const char *argv[]): O2_AUDIODB_INITIALIZERS 11 audioDB::audioDB(const unsigned argc, const char *argv[]): O2_AUDIODB_INITIALIZERS
26 { 12 {
27 if(processArgs(argc, argv)<0){ 13 if(processArgs(argc, argv)<0){
28 printf("No command found.\n"); 14 printf("No command found.\n");
39 // Perform database prefix substitution 25 // Perform database prefix substitution
40 if(dbName && adb_root) 26 if(dbName && adb_root)
41 prefix_name((char** const)&dbName, adb_root); 27 prefix_name((char** const)&dbName, adb_root);
42 28
43 if(O2_ACTION(COM_SERVER)){ 29 if(O2_ACTION(COM_SERVER)){
44 #ifdef LIBRARY
45 ;
46 #else
47 startServer(); 30 startServer();
48 if(SERVER_LSH_INDEX_SINGLETON)
49 delete lsh;
50 #endif
51 } 31 }
52 else if(O2_ACTION(COM_CREATE)) 32 else if(O2_ACTION(COM_CREATE))
53 create(dbName); 33 create(dbName);
54 34
55 else if(O2_ACTION(COM_INSERT)) 35 else if(O2_ACTION(COM_INSERT))
58 else if(O2_ACTION(COM_BATCHINSERT)) 38 else if(O2_ACTION(COM_BATCHINSERT))
59 batchinsert(dbName, inFile); 39 batchinsert(dbName, inFile);
60 40
61 else if(O2_ACTION(COM_QUERY)) 41 else if(O2_ACTION(COM_QUERY))
62 if(isClient){ 42 if(isClient){
63 #ifdef LIBRARY
64 ;
65 #else
66 if(query_from_key){ 43 if(query_from_key){
67 VERB_LOG(1, "Calling web services query %s on database %s, query=%s\n", radius>0?"(Radius)":"(NN)", dbName, (key&&strlen(key))?key:inFile); 44 VERB_LOG(1, "Calling web services query %s on database %s, query=%s\n", radius>0?"(Radius)":"(NN)", dbName, (key&&strlen(key))?key:inFile);
68 ws_query_by_key(dbName, key, inFile, (char*)hostport); 45 ws_query_by_key(dbName, key, inFile, (char*)hostport);
69 } 46 }
70 else{ 47 else{
71 VERB_LOG(1, "Calling web services query on database %s, query=%s\n", dbName, (key&&strlen(key))?key:inFile); 48 VERB_LOG(1, "Calling web services query on database %s, query=%s\n", dbName, (key&&strlen(key))?key:inFile);
72 ws_query(dbName, inFile, (char*)hostport); 49 ws_query(dbName, inFile, (char*)hostport);
73 } 50 }
74 #endif
75 } 51 }
76 else 52 else
77 query(dbName, inFile); 53 query(dbName, inFile);
78 54
79 else if(O2_ACTION(COM_STATUS)) 55 else if(O2_ACTION(COM_STATUS))
80 if(isClient) 56 if(isClient)
81 #ifdef LIBRARY
82 ;
83 #else
84 ws_status(dbName,(char*)hostport); 57 ws_status(dbName,(char*)hostport);
85 #endif
86 else 58 else
87 status(dbName); 59 status(dbName);
88 60
89 else if(O2_ACTION(COM_SAMPLE)) 61 else if(O2_ACTION(COM_SAMPLE))
90 sample(dbName); 62 sample(dbName);
98 else if(O2_ACTION(COM_DUMP)) 70 else if(O2_ACTION(COM_DUMP))
99 dump(dbName); 71 dump(dbName);
100 72
101 else if(O2_ACTION(COM_LISZT)) 73 else if(O2_ACTION(COM_LISZT))
102 if(isClient) 74 if(isClient)
103 #ifdef LIBRARY
104 ;
105 #else
106 ws_liszt(dbName, (char*) hostport); 75 ws_liszt(dbName, (char*) hostport);
107 #endif
108 else 76 else
109 liszt(dbName, lisztOffset, lisztLength); 77 liszt(dbName, lisztOffset, lisztLength);
110 78
111 else if(O2_ACTION(COM_INDEX)) 79 else if(O2_ACTION(COM_INDEX))
112 index_index_db(dbName); 80 index_index_db(dbName);
161 cleanup(); 129 cleanup();
162 throw(err); 130 throw(err);
163 } 131 }
164 } 132 }
165 133
166
167 //for the lib / API
168 audioDB::audioDB(const unsigned argc, const char *argv[], int * apierror): O2_AUDIODB_INITIALIZERS
169 {
170
171 try {
172 UseApiError=1;
173
174 if(processArgs(argc, argv)<0){
175 printf("No command found.\n");
176 cmdline_parser_print_version ();
177 if (strlen(gengetopt_args_info_purpose) > 0)
178 printf("%s\n", gengetopt_args_info_purpose);
179 printf("%s\n", gengetopt_args_info_usage);
180 printf("%s\n", gengetopt_args_info_help[1]);
181 printf("%s\n", gengetopt_args_info_help[2]);
182 printf("%s\n", gengetopt_args_info_help[0]);
183 error("No command found");
184 }
185
186 adb__queryResponse adbq;
187
188 if(O2_ACTION(COM_CREATE))
189 create(dbName);
190
191 else if(O2_ACTION(COM_INSERT))
192 insert(dbName, inFile);
193
194 else if(O2_ACTION(COM_BATCHINSERT))
195 batchinsert(dbName, inFile);
196
197 else if(O2_ACTION(COM_QUERY))
198 if(isClient)
199 ;//ws_query(dbName, inFile, (char*)hostport);
200 else
201 query(dbName, inFile, &adbq);
202 //query(dbName, inFile);
203
204 else if(O2_ACTION(COM_STATUS))
205 if(isClient)
206 ;//ws_status(dbName,(char*)hostport);
207 else
208 status(dbName);
209
210 else if(O2_ACTION(COM_L2NORM))
211 l2norm(dbName);
212
213 else if(O2_ACTION(COM_POWER))
214 power_flag(dbName);
215
216 else if(O2_ACTION(COM_DUMP))
217 dump(dbName);
218
219 else
220 error("Unrecognized command",command);
221
222 } catch(int a) {
223 *apierror=a;
224 return;
225
226 }
227 *apierror=apierrortemp;
228 return;
229
230 }
231
232 //for API status
233 audioDB::audioDB(const unsigned argc, const char *argv[], cppstatusptr stat, int * apierror): O2_AUDIODB_INITIALIZERS
234 {
235
236 try {
237 UseApiError=1;
238
239
240 if(processArgs(argc, argv)<0){
241 printf("No command found.\n");
242 cmdline_parser_print_version ();
243 if (strlen(gengetopt_args_info_purpose) > 0)
244 printf("%s\n", gengetopt_args_info_purpose);
245 printf("%s\n", gengetopt_args_info_usage);
246 printf("%s\n", gengetopt_args_info_help[1]);
247 printf("%s\n", gengetopt_args_info_help[2]);
248 printf("%s\n", gengetopt_args_info_help[0]);
249 error("No command found");
250 }
251
252 status(dbName, stat);
253
254
255 } catch(int a) {
256 *apierror=a;
257 return;
258
259 }
260 *apierror=apierrortemp;
261 return;
262
263 }
264
265
266 //for API query
267 audioDB::audioDB(const unsigned argc, const char *argv[],adb__queryResponse *adbQueryResponse, int * apierror): O2_AUDIODB_INITIALIZERS
268 {
269
270 try {
271 UseApiError=1;
272
273 if(processArgs(argc, argv)<0){
274 printf("No command found.\n");
275 cmdline_parser_print_version ();
276 if (strlen(gengetopt_args_info_purpose) > 0)
277 printf("%s\n", gengetopt_args_info_purpose);
278 printf("%s\n", gengetopt_args_info_usage);
279 printf("%s\n", gengetopt_args_info_help[1]);
280 printf("%s\n", gengetopt_args_info_help[2]);
281 printf("%s\n", gengetopt_args_info_help[0]);
282 error("No command found");
283 }
284
285 query(dbName, inFile, adbQueryResponse);
286
287 } catch(int a) {
288 *apierror=a;
289 return;
290
291 }
292 *apierror=apierrortemp;
293 return;
294
295 }
296
297
298
299
300
301 void audioDB::cleanup() { 134 void audioDB::cleanup() {
302 cmdline_parser_free(&args_info); 135 cmdline_parser_free(&args_info);
303 if(indata)
304 munmap(indata,statbuf.st_size);
305 if(db)
306 munmap(db,getpagesize());
307 if(fileTable) 136 if(fileTable)
308 munmap(fileTable, fileTableLength); 137 munmap(fileTable, fileTableLength);
309 if(trackTable) 138 if(trackTable)
310 munmap(trackTable, trackTableLength); 139 munmap(trackTable, trackTableLength);
311 if(dataBuf)
312 munmap(dataBuf, dataBufLength);
313 if(timesTable) 140 if(timesTable)
314 munmap(timesTable, timesTableLength); 141 munmap(timesTable, timesTableLength);
315 if(powerTable) 142 if(powerTable)
316 munmap(powerTable, powerTableLength); 143 munmap(powerTable, powerTableLength);
317 if(l2normTable) 144 if(l2normTable)
320 munmap(featureFileNameTable, fileTableLength); 147 munmap(featureFileNameTable, fileTableLength);
321 if(timesFileNameTable) 148 if(timesFileNameTable)
322 munmap(timesFileNameTable, fileTableLength); 149 munmap(timesFileNameTable, fileTableLength);
323 if(powerFileNameTable) 150 if(powerFileNameTable)
324 munmap(powerFileNameTable, fileTableLength); 151 munmap(powerFileNameTable, fileTableLength);
325 if(trackOffsetTable)
326 delete [] trackOffsetTable;
327 if(reporter) 152 if(reporter)
328 delete reporter; 153 delete reporter;
329 if(exact_evaluation_queue)
330 delete exact_evaluation_queue;
331 if(allowed_keys) 154 if(allowed_keys)
332 delete allowed_keys; 155 delete allowed_keys;
333 if(rng) 156 if(rng)
334 gsl_rng_free(rng); 157 gsl_rng_free(rng);
335 if(vv)
336 delete vv;
337 if(dbfid>0)
338 close(dbfid);
339 if(infid>0) 158 if(infid>0)
340 close(infid); 159 close(infid);
341 if(dbH) 160 if(adb) {
342 delete dbH; 161 audiodb_close(adb);
343 if(lsh!=SERVER_LSH_INDEX_SINGLETON) 162 adb = NULL;
163 }
164 if(lsh)
344 delete lsh; 165 delete lsh;
345 } 166 }
346 167
347 audioDB::~audioDB(){ 168 audioDB::~audioDB(){
348 cleanup(); 169 cleanup();
741 562
742 return -1; // no command found 563 return -1; // no command found
743 } 564 }
744 565
745 void audioDB::status(const char* dbName, adb__statusResponse *adbStatusResponse){ 566 void audioDB::status(const char* dbName, adb__statusResponse *adbStatusResponse){
746 if(!dbH) 567 adb_status_t status;
747 initTables(dbName, 0); 568 if(!adb) {
748 569 if(!(adb = audiodb_open(dbName, O_RDONLY))) {
749 unsigned dudCount=0; 570 error("Failed to open database file", dbName);
750 unsigned nullCount=0; 571 }
751 for(unsigned k=0; k<dbH->numFiles; k++){ 572 }
752 if(trackTable[k]<sequenceLength){ 573 if(audiodb_status(adb, &status)) {
753 dudCount++; 574 error("Failed to retrieve database status", dbName);
754 if(!trackTable[k])
755 nullCount++;
756 }
757 } 575 }
758 576
759 if(adbStatusResponse == 0) { 577 if(adbStatusResponse == 0) {
760 578 std::cout << "num files:" << status.numFiles << std::endl;
761 // Update Header information 579 std::cout << "data dim:" << status.dim <<std::endl;
762 std::cout << "num files:" << dbH->numFiles << std::endl; 580 if(status.dim > 0) {
763 std::cout << "data dim:" << dbH->dim <<std::endl; 581 size_t bytes_per_vector = sizeof(double) * status.dim;
764 if(dbH->dim>0){ 582 off_t nvectors = status.length / bytes_per_vector;
765 std::cout << "total vectors:" << dbH->length/(sizeof(double)*dbH->dim)<<std::endl; 583 off_t data_region_vectors = status.data_region_size / bytes_per_vector;
766 if(dbH->flags & O2_FLAG_LARGE_ADB) 584 std::cout << "total vectors:" << nvectors << std::endl;
767 std::cout << "vectors available:" << O2_MAX_VECTORS - (dbH->length / (sizeof(double)*dbH->dim)) << std::endl; 585 std::cout << "vectors available:";
768 else 586 if(status.flags & O2_FLAG_LARGE_ADB) {
769 std::cout << "vectors available:" << (dbH->timesTableOffset-(dbH->dataOffset+dbH->length))/(sizeof(double)*dbH->dim) << std::endl; 587 std::cout << O2_MAX_VECTORS - nvectors << std::endl;
770 } 588 } else {
771 if( ! (dbH->flags & O2_FLAG_LARGE_ADB) ){ 589 std::cout << data_region_vectors - nvectors << std::endl;
772 std::cout << "total bytes:" << dbH->length << " (" << (100.0*dbH->length)/(dbH->timesTableOffset-dbH->dataOffset) << "%)" << std::endl; 590 }
773 std::cout << "bytes available:" << dbH->timesTableOffset-(dbH->dataOffset+dbH->length) << " (" << 591 }
774 (100.0*(dbH->timesTableOffset-(dbH->dataOffset+dbH->length)))/(dbH->timesTableOffset-dbH->dataOffset) << "%)" << std::endl; 592 if(!(status.flags & O2_FLAG_LARGE_ADB)) {
775 } 593 double used_frac = ((double) status.length) / status.data_region_size;
776 std::cout << "flags:" << " l2norm[" << DISPLAY_FLAG(dbH->flags&O2_FLAG_L2NORM) 594 std::cout << "total bytes:" << status.length <<
777 << "] minmax[" << DISPLAY_FLAG(dbH->flags&O2_FLAG_MINMAX) 595 " (" << (100.0*used_frac) << "%)" << std::endl;
778 << "] power[" << DISPLAY_FLAG(dbH->flags&O2_FLAG_POWER) 596 std::cout << "bytes available:" << status.data_region_size - status.length <<
779 << "] times[" << DISPLAY_FLAG(dbH->flags&O2_FLAG_TIMES) 597 " (" << (100.0*(1-used_frac)) << "%)" << std::endl;
780 << "] largeADB[" << DISPLAY_FLAG(dbH->flags&O2_FLAG_LARGE_ADB) 598 }
599 std::cout << "flags:" << " l2norm[" << DISPLAY_FLAG(status.flags&O2_FLAG_L2NORM)
600 << "] minmax[" << DISPLAY_FLAG(status.flags&O2_FLAG_MINMAX)
601 << "] power[" << DISPLAY_FLAG(status.flags&O2_FLAG_POWER)
602 << "] times[" << DISPLAY_FLAG(status.flags&O2_FLAG_TIMES)
603 << "] largeADB[" << DISPLAY_FLAG(status.flags&O2_FLAG_LARGE_ADB)
781 << "]" << endl; 604 << "]" << endl;
782 605
783 std::cout << "null count: " << nullCount << " small sequence count " << dudCount-nullCount << std::endl; 606 std::cout << "null count: " << status.nullCount << " small sequence count " << status.dudCount-status.nullCount << std::endl;
784 } else { 607 } else {
785 adbStatusResponse->result.numFiles = dbH->numFiles; 608 adbStatusResponse->result.numFiles = status.numFiles;
786 adbStatusResponse->result.dim = dbH->dim; 609 adbStatusResponse->result.dim = status.dim;
787 adbStatusResponse->result.length = dbH->length; 610 adbStatusResponse->result.length = status.length;
788 adbStatusResponse->result.dudCount = dudCount; 611 adbStatusResponse->result.dudCount = status.dudCount;
789 adbStatusResponse->result.nullCount = nullCount; 612 adbStatusResponse->result.nullCount = status.nullCount;
790 adbStatusResponse->result.flags = dbH->flags; 613 adbStatusResponse->result.flags = status.flags;
791 } 614 }
792 } 615 }
793 616
794 ///used by lib/API 617 void audioDB::l2norm(const char* dbName) {
795 void audioDB::status(const char* dbName, cppstatusptr status){ 618 if(!adb) {
796 if(!dbH) { 619 if(!(adb = audiodb_open(dbName, O_RDWR))) {
797 initTables(dbName, 0); 620 error("Failed to open database file", dbName);
798 } 621 }
799 622 }
800 unsigned dudCount=0; 623 if(audiodb_l2norm(adb)) {
801 unsigned nullCount=0; 624 error("failed to turn on l2norm flag for database", dbName);
802 for(unsigned k=0; k<dbH->numFiles; k++){ 625 }
803 if(trackTable[k]<sequenceLength){ 626 }
804 dudCount++; 627
805 if(!trackTable[k]) 628 void audioDB::power_flag(const char *dbName) {
806 nullCount++; 629 if(!adb) {
807 } 630 if(!(adb = audiodb_open(dbName, O_RDWR))) {
808 } 631 error("Failed to open database file", dbName);
632 }
633 }
634 if(audiodb_power(adb)) {
635 error("can't turn on power flag for database", dbName);
636 }
637 }
638
639 void audioDB::create(const char *dbName) {
640 if(adb) {
641 error("Already have an adb in this object", "");
642 }
643 if(!(adb = audiodb_create(dbName, datasize, ntracks, datadim))) {
644 error("Failed to create database file", dbName);
645 }
646 }
647
648 void audioDB::dump(const char *dbName) {
649 if(!adb) {
650 if(!(adb = audiodb_open(dbName, O_RDONLY))) {
651 error("Failed to open database file", dbName);
652 }
653 }
654 if(audiodb_dump(adb, output)) {
655 error("Failed to dump database to ", output);
656 }
657 status(dbName);
658 }
659
660 void audioDB::insert(const char* dbName, const char* inFile) {
661 if(!adb) {
662 if(!(adb = audiodb_open(dbName, O_RDWR))) {
663 error("failed to open database", dbName);
664 }
665 }
666
667 /* at this point, we have powerfd (an fd), timesFile (a
668 * std::ifstream *) and inFile (a char *). Wacky, huh? Ignore
669 * the wackiness and just use the names. */
670 adb_insert_t insert;
671 insert.features = inFile;
672 insert.times = timesFileName;
673 insert.power = powerFileName;
674 insert.key = key;
675
676 if(audiodb_insert(adb, &insert)) {
677 error("insertion failure", inFile);
678 }
679 status(dbName);
680 }
681
682 void audioDB::batchinsert(const char* dbName, const char* inFile) {
683 if(!adb) {
684 if(!(adb = audiodb_open(dbName, O_RDWR))) {
685 error("failed to open database", dbName);
686 }
687 }
688
689 if(!key)
690 key=inFile;
691 std::ifstream *filesIn = 0;
692 std::ifstream *keysIn = 0;
693
694 if(!(filesIn = new std::ifstream(inFile)))
695 error("Could not open batch in file", inFile);
696 if(key && key!=inFile)
697 if(!(keysIn = new std::ifstream(key)))
698 error("Could not open batch key file",key);
699
700 unsigned totalVectors=0;
701 char *thisFile = new char[MAXSTR];
702 char *thisKey = 0;
703 if (key && (key != inFile)) {
704 thisKey = new char[MAXSTR];
705 }
706 char *thisTimesFileName = new char[MAXSTR];
707 char *thisPowerFileName = new char[MAXSTR];
708
709 do {
710 filesIn->getline(thisFile,MAXSTR);
711 if(key && key!=inFile) {
712 keysIn->getline(thisKey,MAXSTR);
713 } else {
714 thisKey = thisFile;
715 }
716 if(usingTimes) {
717 timesFile->getline(thisTimesFileName,MAXSTR);
718 }
719 if(usingPower) {
720 powerFile->getline(thisPowerFileName, MAXSTR);
721 }
722
723 if(filesIn->eof()) {
724 break;
725 }
726 if(usingTimes){
727 if(timesFile->eof()) {
728 error("not enough timestamp files in timesList", timesFileName);
729 }
730 }
731 if (usingPower) {
732 if(powerFile->eof()) {
733 error("not enough power files in powerList", powerFileName);
734 }
735 }
736 adb_insert_t insert;
737 insert.features = thisFile;
738 insert.times = usingTimes ? thisTimesFileName : NULL;
739 insert.power = usingPower ? thisPowerFileName : NULL;
740 insert.key = thisKey;
741 if(audiodb_insert(adb, &insert)) {
742 error("insertion failure", thisFile);
743 }
744 } while(!filesIn->eof());
745
746 VERB_LOG(0, "%s %s %u vectors %ju bytes.\n", COM_BATCHINSERT, dbName, totalVectors, (intmax_t) (totalVectors * dbH->dim * sizeof(double)));
747
748 delete [] thisPowerFileName;
749 if(key && (key != inFile)) {
750 delete [] thisKey;
751 }
752 delete [] thisFile;
753 delete [] thisTimesFileName;
809 754
810 status->numFiles = dbH->numFiles; 755 delete filesIn;
811 status->dim = dbH->dim; 756 delete keysIn;
812 status->length = dbH->length; 757
813 status->dudCount = dudCount; 758 // Report status
814 status->nullCount = nullCount; 759 status(dbName);
815 status->flags = dbH->flags; 760 }
816 761
817 return; 762 void audioDB::query(const char* dbName, const char* inFile, adb__queryResponse *adbQueryResponse) {
818 } 763
819 764 if(!adb) {
820 765 if(!(adb = audiodb_open(dbName, O_RDWR))) {
821 766 error("failed to open database", dbName);
822 767 }
823 void audioDB::l2norm(const char* dbName) { 768 }
824 forWrite = true; 769
825 initTables(dbName, 0); 770 /* FIXME: we only need this for getting nfiles, which we only need
826 if( !(dbH->flags & O2_FLAG_LARGE_ADB ) && (dbH->length>0) ){ 771 * because the reporters aren't desperately well implemented,
827 /* FIXME: should probably be uint64_t */ 772 * relying on statically-sized vectors rather than adjustable data
828 unsigned numVectors = dbH->length/(sizeof(double)*dbH->dim); 773 * structures. Rework reporter.h to be less lame. */
829 CHECKED_MMAP(double *, dataBuf, dbH->dataOffset, dataBufLength); 774 adb_status_t status;
830 unitNormAndInsertL2(dataBuf, dbH->dim, numVectors, 0); // No append 775 audiodb_status(adb, &status);
831 } 776 uint32_t nfiles = status.numFiles;
832 // Update database flags 777
833 dbH->flags = dbH->flags|O2_FLAG_L2NORM; 778 adb_query_spec_t qspec;
834 memcpy (db, dbH, O2_HEADERSIZE); 779 adb_datum_t datum = {0};
835 } 780
836 781 qspec.refine.flags = 0;
837 void audioDB::power_flag(const char *dbName) { 782 if(trackFile) {
838 forWrite = true; 783 qspec.refine.flags |= ADB_REFINE_INCLUDE_KEYLIST;
839 initTables(dbName, 0); 784 std::vector<const char *> v;
840 if( !(dbH->flags & O2_FLAG_LARGE_ADB ) && (dbH->length>0) ){ 785 char *k = new char[MAXSTR];
841 error("cannot turn on power storage for non-empty database", dbName); 786 trackFile->getline(k, MAXSTR);
842 } 787 while(!trackFile->eof()) {
843 dbH->flags |= O2_FLAG_POWER; 788 v.push_back(k);
844 memcpy(db, dbH, O2_HEADERSIZE); 789 k = new char[MAXSTR];
845 } 790 trackFile->getline(k, MAXSTR);
846 791 }
847 // Unit norm block of features 792 delete [] k;
848 793 qspec.refine.include.nkeys = v.size();
849 /* FIXME: in fact this does not unit norm a block of features, it just 794 qspec.refine.include.keys = new const char *[qspec.refine.include.nkeys];
850 records the L2 norms somewhere. unitNorm() does in fact unit norm 795 for(unsigned int k = 0; k < qspec.refine.include.nkeys; k++) {
851 a block of features. */ 796 qspec.refine.include.keys[k] = v[k];
852 void audioDB::unitNormAndInsertL2(double* X, unsigned dim, unsigned n, unsigned append=0){ 797 }
853 unsigned d; 798 }
854 double *p; 799 if(query_from_key) {
855 unsigned nn = n; 800 qspec.refine.flags |= ADB_REFINE_EXCLUDE_KEYLIST;
856 801 qspec.refine.exclude.nkeys = 1;
857 assert(l2normTable); 802 qspec.refine.exclude.keys = &key;
858 803 }
859 if( !(dbH->flags & O2_FLAG_LARGE_ADB) && !append && (dbH->flags & O2_FLAG_L2NORM) ) 804 if(radius) {
860 error("Database is already L2 normed", "automatic norm on insert is enabled"); 805 qspec.refine.flags |= ADB_REFINE_RADIUS;
861 806 qspec.refine.radius = radius;
862 VERB_LOG(2, "norming %u vectors...", n); 807 }
863 808 if(use_absolute_threshold) {
864 double* l2buf = new double[n]; 809 qspec.refine.flags |= ADB_REFINE_ABSOLUTE_THRESHOLD;
865 double* l2ptr = l2buf; 810 qspec.refine.absolute_threshold = absolute_threshold;
866 assert(l2buf); 811 }
867 assert(X); 812 if(use_relative_threshold) {
868 813 qspec.refine.flags |= ADB_REFINE_RELATIVE_THRESHOLD;
869 while(nn--){ 814 qspec.refine.relative_threshold = relative_threshold;
870 p=X; 815 }
871 *l2ptr=0.0; 816 if(usingTimes) {
872 d=dim; 817 qspec.refine.flags |= ADB_REFINE_DURATION_RATIO;
873 while(d--){ 818 qspec.refine.duration_ratio = timesTol;
874 *l2ptr+=*p**p; 819 }
875 p++; 820 /* FIXME: not sure about this any more; maybe it belongs in
876 } 821 query_id? Or maybe we just don't need a flag for it? */
877 l2ptr++; 822 qspec.refine.hopsize = sequenceHop;
878 X+=dim; 823 if(sequenceHop != 1) {
879 } 824 qspec.refine.flags |= ADB_REFINE_HOP_SIZE;
880 unsigned offset; 825 }
881 if(append) { 826
882 // FIXME: a hack, a very palpable hack: the vectors have already 827 if(query_from_key) {
883 // been inserted, and dbH->length has already been updated. We 828 datum.key = key;
884 // need to subtract off again the number of vectors that we've
885 // inserted this time...
886 offset=(dbH->length/(dbH->dim*sizeof(double)))-n; // number of vectors
887 } else { 829 } else {
888 offset=0; 830 int fd;
889 } 831 struct stat st;
890 memcpy(l2normTable+offset, l2buf, n*sizeof(double)); 832
891 if(l2buf) 833 /* FIXME: around here there are all sorts of hideous leaks. */
892 delete[] l2buf; 834 fd = open(inFile, O_RDONLY);
893 VERB_LOG(2, " done."); 835 if(fd < 0) {
836 error("failed to open feature file", inFile);
837 }
838 fstat(fd, &st);
839 read(fd, &datum.dim, sizeof(uint32_t));
840 datum.nvectors = (st.st_size - sizeof(uint32_t)) / (datum.dim * sizeof(double));
841 datum.data = (double *) malloc(st.st_size - sizeof(uint32_t));
842 read(fd, datum.data, st.st_size - sizeof(uint32_t));
843 close(fd);
844 if(usingPower) {
845 uint32_t one;
846 fd = open(powerFileName, O_RDONLY);
847 if(fd < 0) {
848 error("failed to open power file", powerFileName);
849 }
850 read(fd, &one, sizeof(uint32_t));
851 if(one != 1) {
852 error("malformed power file dimensionality", powerFileName);
853 }
854 datum.power = (double *) malloc(datum.nvectors * sizeof(double));
855 if(read(fd, datum.power, datum.nvectors * sizeof(double)) != (ssize_t) (datum.nvectors * sizeof(double))) {
856 error("malformed power file", powerFileName);
857 }
858 close(fd);
859 }
860 if(usingTimes) {
861 datum.times = (double *) malloc(2 * datum.nvectors * sizeof(double));
862 insertTimeStamps(datum.nvectors, timesFile, datum.times);
863 }
864 }
865
866 qspec.qid.datum = &datum;
867 qspec.qid.sequence_length = sequenceLength;
868 qspec.qid.flags = 0;
869 qspec.qid.flags |= usingQueryPoint ? 0 : ADB_QID_FLAG_EXHAUSTIVE;
870 qspec.qid.flags |= lsh_exact ? 0 : ADB_QID_FLAG_ALLOW_FALSE_POSITIVES;
871 qspec.qid.sequence_start = queryPoint;
872
873 switch(queryType) {
874 case O2_POINT_QUERY:
875 qspec.qid.sequence_length = 1;
876 qspec.params.accumulation = ADB_ACCUMULATION_DB;
877 qspec.params.distance = ADB_DISTANCE_DOT_PRODUCT;
878 qspec.params.npoints = pointNN;
879 qspec.params.ntracks = 0;
880 reporter = new pointQueryReporter< std::greater < NNresult > >(pointNN);
881 break;
882 case O2_TRACK_QUERY:
883 qspec.qid.sequence_length = 1;
884 qspec.params.accumulation = ADB_ACCUMULATION_PER_TRACK;
885 qspec.params.distance = ADB_DISTANCE_DOT_PRODUCT;
886 qspec.params.npoints = pointNN;
887 qspec.params.ntracks = trackNN;
888 reporter = new trackAveragingReporter< std::greater< NNresult > >(pointNN, trackNN, nfiles);
889 break;
890 case O2_SEQUENCE_QUERY:
891 case O2_N_SEQUENCE_QUERY:
892 qspec.params.accumulation = ADB_ACCUMULATION_PER_TRACK;
893 qspec.params.distance = no_unit_norming ? ADB_DISTANCE_EUCLIDEAN : ADB_DISTANCE_EUCLIDEAN_NORMED;
894 qspec.params.npoints = pointNN;
895 qspec.params.ntracks = trackNN;
896 switch(queryType) {
897 case O2_SEQUENCE_QUERY:
898 if(!(qspec.refine.flags & ADB_REFINE_RADIUS)) {
899 reporter = new trackAveragingReporter< std::less< NNresult > >(pointNN, trackNN, nfiles);
900 } else {
901 reporter = new trackSequenceQueryRadReporter(trackNN, nfiles);
902 }
903 break;
904 case O2_N_SEQUENCE_QUERY:
905 if(!(qspec.refine.flags & ADB_REFINE_RADIUS)) {
906 reporter = new trackSequenceQueryNNReporter< std::less < NNresult > >(pointNN, trackNN, nfiles);
907 } else {
908 reporter = new trackSequenceQueryRadNNReporter(pointNN, trackNN, nfiles);
909 }
910 break;
911 }
912 break;
913 case O2_ONE_TO_ONE_N_SEQUENCE_QUERY:
914 qspec.params.accumulation = ADB_ACCUMULATION_ONE_TO_ONE;
915 qspec.params.distance = no_unit_norming ? ADB_DISTANCE_EUCLIDEAN : ADB_DISTANCE_EUCLIDEAN_NORMED;
916 qspec.params.npoints = 0;
917 qspec.params.ntracks = 0;
918 if(!(qspec.refine.flags & ADB_REFINE_RADIUS)) {
919 error("query-type not yet supported");
920 } else {
921 reporter = new trackSequenceQueryRadNNReporterOneToOne(pointNN,trackNN, dbH->numFiles);
922 }
923 break;
924 default:
925 error("unrecognized queryType");
926 }
927
928 adb_query_results_t *rs = audiodb_query_spec(adb, &qspec);
929
930 // FIXME: free bits of datum if !query_from_key
931
932 if(rs == NULL) {
933 error("audiodb_query_spec failed");
934 }
935
936 for(unsigned int k = 0; k < rs->nresults; k++) {
937 adb_result_t r = rs->results[k];
938 reporter->add_point(audiodb_key_index(adb, r.key), r.qpos, r.ipos, r.dist);
939 }
940 audiodb_query_free_results(adb, &qspec, rs);
941
942 reporter->report(adb, adbQueryResponse);
894 } 943 }
895 944
896 // This entry point is visited once per instance 945 // This entry point is visited once per instance
897 // so it is a good place to set any global state variables 946 // so it is a good place to set any global state variables
898 int main(const int argc, const char* argv[]){ 947 int main(const int argc, const char* argv[]){
899 SERVER_LSH_INDEX_SINGLETON = 0; // Initialize global variables
900 SERVER_ADB_ROOT = 0; // Server-side database root prefix 948 SERVER_ADB_ROOT = 0; // Server-side database root prefix
901 SERVER_ADB_FEATURE_ROOT = 0; // Server-side features root prefix 949 SERVER_ADB_FEATURE_ROOT = 0; // Server-side features root prefix
902 audioDB(argc, argv); 950 audioDB(argc, argv);
903 } 951 }
904
905
906 extern "C" {
907
908 /* for API questions contact
909 * Christophe Rhodes c.rhodes@gold.ac.uk
910 * Ian Knopke mas01ik@gold.ac.uk, ian.knopke@gmail.com */
911
912 #include "audioDB_API.h"
913
914 adb_ptr audiodb_create(const char *path, unsigned datasize, unsigned ntracks, unsigned datadim) {
915 const char *argv[12];
916 int argvctr=0;
917 char tempstr1[200];
918 char tempstr2[200];
919 char tempstr3[200];
920 int apierror=0;
921
922
923 argv[argvctr++] = "audioDB";
924 argv[argvctr++] = "--NEW";
925 argv[argvctr++] = "-d";
926 argv[argvctr++] = path;
927
928 if (datasize >0){
929 argv[argvctr++]="--datasize";
930 snprintf(tempstr1,sizeof(tempstr1),"%u",datasize);
931 argv[argvctr++]=tempstr1;
932 }
933
934 if (ntracks >0){
935 argv[argvctr++]="--ntracks";
936 snprintf(tempstr2,sizeof(tempstr2),"%u",ntracks);
937 argv[argvctr++]=tempstr2;
938 }
939
940 if (datadim > 0){
941 argv[argvctr++]="--datadim";
942 snprintf(tempstr3,sizeof(tempstr3),"%u",datadim);
943 argv[argvctr++]=tempstr3;
944 }
945
946 argv[argvctr]='\0';
947
948 audioDB::audioDB(argvctr, argv, &apierror);
949
950 if (!apierror){
951 return audiodb_open(path);
952 }
953
954 /* database exists, so fail and pass NULL */
955 return NULL;
956 }
957
958
959
960 int audiodb_insert(adb_ptr mydb, adb_insert_ptr ins) {
961 const char *argv[15];
962 int argvctr=0;
963 int apierror=0;
964
965 argv[argvctr++]="audioDB";
966 argv[argvctr++]="-I";
967 argv[argvctr++]="-d";
968 argv[argvctr++]=mydb->dbname;
969 argv[argvctr++]="-f";
970 argv[argvctr++]=ins->features;
971
972 if (ins->times){
973 argv[argvctr++]="--times";
974 argv[argvctr++]=ins->times;
975 }
976
977 if (ins->power){
978 argv[argvctr++]="-w";
979 argv[argvctr++]=ins->power;
980 }
981
982 if (ins->key){
983 argv[argvctr++]="--key";
984 argv[argvctr++]=ins->key;
985 }
986 argv[argvctr]='\0';
987
988 audioDB::audioDB(argvctr,argv,&apierror);
989 return apierror;
990 }
991
992
993 int audiodb_batchinsert(adb_ptr mydb, adb_insert_ptr ins, unsigned int size) {
994
995 const char *argv[22];
996 int argvctr=0;
997 unsigned int i=0;
998 char tempfeaturename[]="tempfeatureXXXXXX";
999 char temppowername[]="temppowerXXXXXX";
1000 char tempkeyname[]="tempkeyXXXXXX";
1001 char temptimesname[]="temptimesXXXXXX";
1002 int tempfeaturefd = -1;
1003 int temppowerfd = -1;
1004 int tempkeyfd = -1;
1005 int temptimesfd = -1;
1006
1007 int flags[4]={0};
1008 int apierror=0;
1009
1010 /* So the final API should take an array of structs. However, the current
1011 * version requires four separate text files. So temporarily, we need to
1012 * unpack the struct array, make four separate text files, and then reinsert
1013 * them into the command-line call. This should change as soon as possible */
1014
1015
1016 argv[argvctr++]="audioDB";
1017 argv[argvctr++]="-B";
1018 argv[argvctr++]="-d";
1019 argv[argvctr++]=mydb->dbname;
1020
1021
1022 /* assume struct is well formed for all entries */
1023 if (ins[0].features){ flags[0]++;} else {
1024 /* short circuit the case where there are no features in the structs */
1025 return -1;
1026 } ;
1027 if (ins[0].power){ flags[1]++;};
1028 if (ins[0].key){ flags[2]++;};
1029 if (ins[0].times){ flags[3]++;};
1030
1031
1032 /* make four temp files */
1033 if ((tempfeaturefd = mkstemp(tempfeaturename)) == -1)
1034 goto error;
1035 if ((temppowerfd = mkstemp(temppowername)) == -1)
1036 goto error;
1037 if ((tempkeyfd=mkstemp(tempkeyname)) == -1)
1038 goto error;
1039 if ((temptimesfd=mkstemp(temptimesname)) == -1)
1040 goto error;
1041
1042 /* Ok, so we should have a working set of files to write to */
1043 /* I'm going to assume that the same format is kept for all structs in the array */
1044 /* 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 */
1045 for (i = 0; i < size; i++) {
1046 if (write(tempfeaturefd,ins[i].features,strlen(ins[i].features)) != (ssize_t) strlen(ins[i].features))
1047 goto error;
1048 if (write(tempfeaturefd,"\n",1) != 1)
1049 goto error;
1050
1051 if (flags[1]) {
1052 if (write(temppowerfd,ins[i].power,strlen(ins[i].power)) != (ssize_t) strlen(ins[i].power))
1053 goto error;
1054 if (write(temppowerfd,"\n",1) != 1)
1055 goto error;
1056 }
1057 if (flags[2]) {
1058 if (write(tempkeyfd,ins[i].key,strlen(ins[i].key)) != (ssize_t) strlen(ins[i].key))
1059 goto error;
1060 if (write(tempkeyfd,"\n",1) != 1)
1061 goto error;
1062 }
1063 if (flags[3]) {
1064 if (write(temptimesfd,ins[i].times,strlen(ins[i].times)) != (ssize_t) strlen(ins[i].times))
1065 goto error;
1066 if (write(temptimesfd,"\n",1) != 1)
1067 goto error;
1068 }
1069 }
1070
1071 argv[argvctr++]="-F";
1072 argv[argvctr++]=tempfeaturename;
1073 close(tempfeaturefd);
1074 close(temppowerfd);
1075 close(tempkeyfd);
1076 close(temptimesfd);
1077
1078 if (flags[1]){
1079 argv[argvctr++]="--powerList";
1080 argv[argvctr++]=temppowername;
1081 }
1082
1083 if (flags[2]){
1084 argv[argvctr++]="--keyList";
1085 argv[argvctr++]=tempkeyname;
1086 }
1087
1088 if (flags[3]){
1089 argv[argvctr++]="--timesList";
1090 argv[argvctr++]=temptimesname;
1091 }
1092
1093 argv[argvctr]='\0';
1094
1095 audioDB::audioDB(argvctr,argv,&apierror);
1096
1097 remove(tempfeaturename);
1098 remove(temppowername);
1099 remove(tempkeyname);
1100 remove(temptimesname);
1101
1102
1103 return apierror;
1104
1105 error:
1106 if(tempfeaturefd != -1) {
1107 close(tempfeaturefd);
1108 remove(tempfeaturename);
1109 }
1110 if(temppowerfd != -1) {
1111 close(temppowerfd);
1112 remove(temppowername);
1113 }
1114 if(tempkeyfd != -1) {
1115 close(tempkeyfd);
1116 remove(tempkeyname);
1117 }
1118 if(temptimesfd != -1) {
1119 close(temptimesfd);
1120 remove(temptimesname);
1121 }
1122 return -1;
1123 }
1124
1125
1126 int audiodb_query(adb_ptr mydb, adb_query_ptr adbq, adb_queryresult_ptr adbqr){
1127
1128 const char *argv[32];
1129 int argvctr=0;
1130 char tempstr1[200];
1131 char tempstr2[200];
1132 char tempstr3[200];
1133 int apierror=0;
1134
1135 adb__queryResponse adbQueryResponse;
1136
1137 /* TODO: may need error checking here */
1138 /* currently counting on audioDB binary to fail for me */
1139 argv[argvctr++]="audioDB";
1140
1141 if(adbq->querytype){
1142 argv[argvctr++]="-Q";
1143 argv[argvctr++]=adbq->querytype;
1144 }
1145
1146 if(mydb->dbname){
1147 argv[argvctr++]="-d";
1148 argv[argvctr++]=mydb->dbname;
1149 }
1150
1151 if (adbq->feature){
1152 argv[argvctr++]="-f";
1153 argv[argvctr++]=adbq->feature;
1154 }
1155
1156 if (adbq->key){
1157 argv[argvctr++]="-k";
1158 argv[argvctr++]=adbq->key;
1159 }
1160
1161 if (adbq->power){
1162 argv[argvctr++]="-w";
1163 argv[argvctr++]=adbq->power;
1164 }
1165
1166 if (adbq->qpoint){
1167 argv[argvctr++]="-p";
1168 argv[argvctr++]=adbq->qpoint;
1169 }
1170 if (adbq->numpoints){
1171 argv[argvctr++]="-n";
1172 argv[argvctr++]=adbq->numpoints;
1173 }
1174 if (adbq->radius){
1175 argv[argvctr++]="-R";
1176 argv[argvctr++]=adbq->radius;
1177 }
1178 if(adbq->resultlength){
1179 argv[argvctr++]="-r";
1180 argv[argvctr++]=adbq->resultlength;
1181 }
1182 if(adbq->sequencelength){
1183 argv[argvctr++]="-l";
1184 argv[argvctr++]=adbq->sequencelength;
1185 }
1186 if(adbq->sequencehop){
1187 argv[argvctr++]="-h";
1188 argv[argvctr++]=adbq->sequencehop;
1189 }
1190
1191 if (adbq->absolute_threshold){
1192 argv[argvctr++]="--absolute-threshold";
1193 snprintf(tempstr1,sizeof(tempstr1),"%f",adbq->absolute_threshold);
1194 argv[argvctr++]=tempstr1;
1195 }
1196
1197 if (adbq->relative_threshold){
1198 argv[argvctr++]="--relative-threshold";
1199 snprintf(tempstr2,sizeof(tempstr2),"%f",adbq->relative_threshold);
1200 argv[argvctr++]=tempstr2;
1201 }
1202
1203 if (adbq->exhaustive){
1204 argv[argvctr++]="--exhaustive";
1205 }
1206
1207 if (adbq->expandfactor){
1208 argv[argvctr++]="--expandfactor";
1209 snprintf(tempstr3,sizeof(tempstr3),"%f",adbq->expandfactor);
1210 argv[argvctr++]=tempstr3;
1211 }
1212
1213 if (adbq->rotate){
1214 argv[argvctr++]="--rotate";
1215 }
1216
1217 if (adbq->keylist){
1218 argv[argvctr++]="-K";
1219 argv[argvctr++]=adbq->keylist;
1220 }
1221 argv[argvctr]='\0';
1222
1223 /* debugging */
1224
1225 audioDB::audioDB(argvctr,argv, &adbQueryResponse, &apierror);
1226
1227 //copy data over here from adbQueryResponse to adbqr
1228 adbqr->sizeRlist=adbQueryResponse.result.__sizeRlist;
1229 adbqr->sizeDist=adbQueryResponse.result.__sizeDist;
1230 adbqr->sizeQpos=adbQueryResponse.result.__sizeQpos;
1231 adbqr->sizeSpos=adbQueryResponse.result.__sizeSpos;
1232 adbqr->Rlist=adbQueryResponse.result.Rlist;
1233 adbqr->Dist=adbQueryResponse.result.Dist;
1234 adbqr->Qpos=adbQueryResponse.result.Qpos;
1235 adbqr->Spos=adbQueryResponse.result.Spos;
1236
1237 return apierror;
1238 }
1239
1240 ///* status command */
1241 int audiodb_status(adb_ptr mydb, adb_status_ptr status){
1242
1243 cppstatus sss;
1244 int apierror=0;
1245
1246 const char *argv[5];
1247
1248 apierror=0;
1249 argv[0]="audioDB";
1250 argv[1]="--STATUS";
1251 argv[2]="-d";
1252 argv[3]=mydb->dbname;
1253 argv[4]='\0';
1254
1255 audioDB::audioDB(4,argv,&sss ,&apierror);
1256
1257 status->numFiles=sss.numFiles;
1258 status->dim=sss.dim;
1259 status->length=sss.length;
1260 status->dudCount=sss.dudCount;
1261 status->nullCount=sss.nullCount;
1262 status->flags=sss.flags;
1263
1264 return apierror;
1265 }
1266
1267 int audiodb_dump(adb_ptr mydb){
1268 return audiodb_dump_withdir(mydb,"audioDB.dump");
1269 }
1270
1271 int audiodb_dump_withdir(adb_ptr mydb, const char *outputdir){
1272
1273 const char *argv[7];
1274 int argvctr=0;
1275 int apierror=0;
1276
1277 argv[argvctr++]="audioDB";
1278 argv[argvctr++]="--DUMP";
1279 argv[argvctr++]="-d";
1280 argv[argvctr++]=mydb->dbname;
1281 argv[argvctr++]="--output";
1282 argv[argvctr++]=(char *)outputdir;
1283 argv[argvctr]='\0';
1284
1285 audioDB::audioDB(6,argv,&apierror);
1286
1287 return apierror;
1288 }
1289
1290 int audiodb_l2norm(adb_ptr mydb){
1291
1292 const char *argv[5];
1293 int apierror=0;
1294
1295 argv[0]="audioDB";
1296 argv[1]="--L2NORM";
1297 argv[2]="-d";
1298 argv[3]=mydb->dbname;
1299 argv[4]='\0';
1300
1301 audioDB::audioDB(4,argv,&apierror);
1302 return apierror;
1303 }
1304
1305 int audiodb_power(adb_ptr mydb){
1306
1307 const char *argv[5];
1308 int apierror=0;
1309
1310 argv[0]="audioDB";
1311 argv[1]="--POWER";
1312 argv[2]="-d";
1313 argv[3]=mydb->dbname;
1314 argv[4]='\0';
1315
1316 audioDB::audioDB(4,argv,&apierror);
1317 return apierror;
1318 }
1319
1320 adb_ptr audiodb_open(const char *path){
1321
1322 adb_ptr mydbp;
1323 adbstatus mystatus;
1324
1325 /* if db exists */
1326
1327 if (open(path, O_EXCL) != -1){
1328
1329 mydbp=(adb_ptr)malloc(sizeof(adb));
1330 mydbp->dbname=(char *)malloc(1+strlen(path));
1331
1332 strcpy(mydbp->dbname,path);
1333
1334 audiodb_status(mydbp, &mystatus);
1335 mydbp->ntracks=mystatus.numFiles;
1336 mydbp->datadim=mystatus.dim;
1337
1338 return mydbp;
1339 }
1340
1341 return NULL;
1342 };
1343
1344
1345
1346 void audiodb_close(adb_ptr db){
1347
1348 free(db->dbname);
1349 free(db);
1350
1351 }
1352
1353
1354 }
1355