annotate common/FeatureFileIndex.cpp @ 53:bcea875d8d2f tip

More build fixes
author Chris Cannam
date Thu, 16 Oct 2014 19:03:51 +0100
parents e0e12bd2978d
children
rev   line source
Chris@44 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@44 2
Chris@44 3 #include "FeatureFileIndex.h"
Chris@44 4 #include "TypeRegistrar.h"
Chris@44 5
Chris@44 6 #include <QMutexLocker>
Chris@44 7 #include <QDir>
Chris@44 8
Chris@44 9 #include "base/TempDirectory.h"
Chris@44 10 #include "base/Exceptions.h"
Chris@44 11
Chris@44 12 using namespace Dataquay;
Chris@44 13
Chris@44 14
Chris@44 15 namespace ClassicalData {
Chris@44 16
Chris@44 17 FeatureFileIndex *
Chris@44 18 FeatureFileIndex::getInstance()
Chris@44 19 {
Chris@44 20 static FeatureFileIndex instance;
Chris@44 21 return &instance;
Chris@44 22 }
Chris@44 23
Chris@44 24 FeatureFileIndex::FeatureFileIndex() :
Chris@45 25 m_bs(0),
Chris@44 26 m_index(0)
Chris@44 27 {
Chris@44 28 try {
Chris@44 29 m_indexFileName = getIndexFileName();
Chris@44 30 } catch (DirectoryCreationFailed f) {
Chris@44 31 std::cerr << "FeatureFileIndex: ERROR: Failed to find or create index directory: " << f.what() << std::endl;
Chris@44 32 return;
Chris@44 33 }
Chris@44 34
Chris@45 35 m_bs = new BasicStore;
Chris@52 36 m_bs->setBaseUri(Uri(QUrl::fromLocalFile(m_indexFileName)));
Chris@52 37
Chris@45 38 m_index = new TransactionalStore(m_bs);
Chris@44 39
Chris@45 40 TypeRegistrar::addMappings(m_bs, 0);
Chris@44 41
Chris@44 42 if (QFile(m_indexFileName).exists()) {
Chris@45 43 m_bs->import(QUrl::fromLocalFile(m_indexFileName),
Chris@45 44 BasicStore::ImportIgnoreDuplicates);
Chris@44 45 //!!! catch
Chris@44 46 }
Chris@44 47 }
Chris@44 48
Chris@44 49 FeatureFileIndex::~FeatureFileIndex()
Chris@44 50 {
Chris@45 51 delete m_index;
Chris@45 52 delete m_bs;
Chris@44 53 }
Chris@44 54
Chris@44 55 QString
Chris@44 56 FeatureFileIndex::getIndexFileName()
Chris@44 57 {
Chris@44 58 QDir d = TempDirectory::getInstance()->getContainingPath();
Chris@44 59 QString n("index");
Chris@44 60 QFileInfo fi(d.filePath(n));
Chris@44 61
Chris@44 62 if ((fi.exists() && !fi.isDir()) ||
Chris@44 63 (!fi.exists() && !d.mkdir(n))) {
Chris@44 64 throw DirectoryCreationFailed(fi.filePath());
Chris@44 65 }
Chris@44 66
Chris@44 67 return QDir(fi.filePath()).filePath("features.ttl");
Chris@44 68 }
Chris@44 69
Chris@44 70 QString
Chris@44 71 FeatureFileIndex::getFeatureDirectoryName()
Chris@44 72 {
Chris@44 73 QDir d = TempDirectory::getInstance()->getContainingPath();
Chris@44 74 QString n("features");
Chris@44 75 QFileInfo fi(d.filePath(n));
Chris@44 76
Chris@44 77 if ((fi.exists() && !fi.isDir()) ||
Chris@44 78 (!fi.exists() && !d.mkdir(n))) {
Chris@44 79 throw DirectoryCreationFailed(fi.filePath());
Chris@44 80 }
Chris@44 81
Chris@44 82 return fi.filePath();
Chris@44 83 }
Chris@44 84
Chris@44 85 void
Chris@45 86 FeatureFileIndex::loadFor(AudioFile *tf, Store *store)
Chris@44 87 {
Chris@44 88 if (!m_index) {
Chris@44 89 std::cerr << "FeatureFileIndex::loadFor: No index!" << std::endl;
Chris@44 90 return;
Chris@44 91 }
Chris@44 92 updateIndex();
Chris@44 93
Chris@46 94 QSet<Uri> fileUris;
Chris@46 95
Chris@46 96 // The same file may be referred to with more than one URI; we
Chris@46 97 // want to load any or all of: the URI in our file object; encoded
Chris@46 98 // version of same; and any other file that is recorded as having
Chris@46 99 // the same hash (i.e. it is the same file).
Chris@46 100
Chris@46 101 fileUris.insert(tf->uri());
Chris@46 102
Chris@46 103 // and again with encoded version of file URI
Chris@46 104 QByteArray enc = QUrl(tf->uri().toString()).toEncoded();
Chris@46 105 fileUris.insert(Uri(QString::fromUtf8(enc)));
Chris@46 106
Chris@46 107 // and again with anything else having the same hash
Chris@46 108 if (tf->hash() != "") {
Chris@52 109 Triple pattern(Node(), store->expand("foaf:sha1"), Node(tf->hash()));
Chris@46 110 Triples results = m_index->match(pattern);
Chris@46 111 std::cerr << "FeatureFileIndex::loadFor: " << results.size() << " audio file(s) found with hash " << tf->hash().toStdString() << std::endl;
Chris@46 112 foreach (Triple t, results) {
Chris@46 113 fileUris.insert(Uri(t.a.value));
Chris@46 114 }
Chris@46 115 }
Chris@46 116
Chris@46 117 foreach (Uri u, fileUris) {
Chris@46 118 loadFor(tf->uri(), u, tf->hash(), store);
Chris@46 119 }
Chris@46 120 }
Chris@46 121
Chris@46 122 bool
Chris@46 123 FeatureFileIndex::loadFor(Uri canonicalUri, Uri afuri,
Chris@46 124 QString hash, Store *store)
Chris@46 125 {
Chris@45 126 // The AudioFile object has a URI and a hash. Feature files
Chris@45 127 // generated for this AudioFile should ideally have a matching
Chris@45 128 // hash; if they have no hash, then the URI should match. If the
Chris@45 129 // hash is present in the feature file but does not match, then it
Chris@45 130 // cannot be the right track even if the URI matches.
Chris@45 131
Chris@52 132 Triple pattern(Node(), store->expand("foaf:primaryTopic"), afuri);
Chris@46 133 Triples results = m_index->match(pattern);
Chris@46 134 std::cerr << "FeatureFileIndex::loadFor: " << results.size() << " feature file(s) for audio file " << afuri << std::endl;
Chris@45 135
Chris@46 136 bool loadedSomething = false;
Chris@45 137
Chris@46 138 foreach (Triple t, results) {
Chris@46 139 try {
Chris@46 140 BasicStore *b = BasicStore::load(QUrl(t.a.value));
Chris@46 141 Triples ts = b->match
Chris@52 142 (Triple(afuri, store->expand("a"), m_index->expand("mo:AudioFile")));
Chris@46 143 std::cerr << "FeatureFileIndex::loadFor: feature file "
Chris@46 144 << t.a << " has " << ts.size() << " type node(s) for this audio file" << std::endl;
Chris@46 145 bool someGood = false;
Chris@46 146 foreach (Triple t, ts) {
Chris@46 147 bool good = true;
Chris@46 148 if (hash != "") {
Chris@46 149 Triples hashts = b->match
Chris@46 150 (Triple(afuri, m_index->expand("foaf:sha1"), Node()));
Chris@46 151 std::cerr << "FeatureFileIndex::loadFor: feature file "
Chris@46 152 << t.a << " has " << hashts.size() << " hashes for this file" << std::endl;
Chris@46 153 if (!hashts.empty()) {
Chris@46 154 good = false;
Chris@46 155 foreach (Triple hasht, hashts) {
Chris@46 156 if (hasht.c.value == hash) {
Chris@46 157 std::cerr << "Hash " << hasht.c << " matches our hash " << hash.toStdString() << std::endl;
Chris@46 158 good = true;
Chris@46 159 break;
Chris@46 160 }
Chris@46 161 }
Chris@46 162 if (!good) {
Chris@46 163 std::cerr << "(no hash matches, eliminating file)" << std::endl;
Chris@46 164 }
Chris@46 165 } else {
Chris@46 166 std::cerr << "(so cannot eliminate file via hash)" << std::endl;
Chris@46 167 }
Chris@46 168 }
Chris@46 169 if (good) {
Chris@46 170 std::cerr << "...going to import this one" << std::endl;
Chris@46 171 someGood = true;
Chris@46 172 }
Chris@46 173 }
Chris@46 174 if (someGood) {
Chris@46 175 Triples all = b->match(Triple());
Chris@46 176 std::cerr << "Importing " << all.size() << " triple(s) into store" << std::endl;
Chris@46 177 // Replace instances of the audio file URI with our
Chris@46 178 // canonical URI (we want to make sure we're
Chris@46 179 // associating these facts with our own URI for this
Chris@46 180 // file, even if they originated from a different URI
Chris@46 181 // with the same hash)
Chris@52 182 Node from = Node(Uri(afuri.toString()));
Chris@52 183 Node to = Node(Uri(canonicalUri.toString()));
Chris@46 184 foreach (Triple t, all) {
Chris@46 185 if (t.a == from) t.a = to;
Chris@46 186 if (t.c == from) t.c = to;
Chris@46 187 store->add(t);
Chris@46 188 }
Chris@46 189 loadedSomething = true;
Chris@46 190 }
Chris@46 191 } catch (...) { }
Chris@45 192 }
Chris@45 193
Chris@46 194 return loadedSomething;
Chris@44 195 }
Chris@44 196
Chris@44 197 void
Chris@45 198 FeatureFileIndex::featureFileAdded(QString filepath)
Chris@45 199 {
Chris@45 200 index(QUrl::fromLocalFile(filepath));
Chris@45 201 }
Chris@45 202
Chris@45 203 void
Chris@44 204 FeatureFileIndex::updateIndex()
Chris@44 205 {
Chris@44 206 QMutexLocker locker(&m_mutex);
Chris@44 207 if (!m_index) return;
Chris@44 208
Chris@46 209 std::cerr << "Generating index..." << std::endl;
Chris@46 210
Chris@44 211 QDir featureDir;
Chris@44 212 try {
Chris@44 213 QString s = getFeatureDirectoryName();
Chris@44 214 featureDir = QDir(s);
Chris@44 215 } catch (DirectoryCreationFailed f) {
Chris@44 216 std::cerr << "FeatureFileIndex::updateIndex: ERROR: Failed to find or create feature directory: " << f.what() << std::endl;
Chris@44 217 return;
Chris@44 218 }
Chris@44 219
Chris@44 220 featureDir.setFilter(QDir::Files);
Chris@44 221
Chris@44 222 for (unsigned int i = 0; i < featureDir.count(); ++i) {
Chris@44 223 QFileInfo fi(featureDir.filePath(featureDir[i]));
Chris@44 224 if (fi.isFile() && fi.isReadable()) {
Chris@45 225 index(QUrl::fromLocalFile(fi.filePath()));
Chris@44 226 }
Chris@44 227 }
Chris@44 228
Chris@44 229 //!!! remove triples from index that refer to nonexistent files?
Chris@44 230
Chris@44 231 std::cerr << "Saving index to " << m_indexFileName.toStdString() << std::endl;
Chris@45 232 m_bs->save(m_indexFileName);
Chris@46 233
Chris@46 234 std::cerr << "Done" << std::endl;
Chris@45 235 }
Chris@45 236
Chris@45 237 void
Chris@45 238 FeatureFileIndex::index(QUrl fileUrl)
Chris@45 239 {
Chris@52 240 Triple typeTriple(Uri(fileUrl), m_index->expand("a"), m_index->expand("foaf:Document"));
Chris@45 241
Chris@45 242 if (m_index->contains(typeTriple)) {
Chris@45 243 return;
Chris@45 244 }
Chris@45 245
Chris@45 246 Transaction *tx = m_index->startTransaction();
Chris@45 247 tx->add(typeTriple);
Chris@45 248
Chris@45 249 try {
Chris@45 250 BasicStore *b = BasicStore::load(fileUrl);
Chris@45 251 Triples ts = b->match
Chris@52 252 (Triple(Node(), m_index->expand("a"), m_index->expand("mo:AudioFile")));
Chris@45 253 foreach (Triple t, ts) {
Chris@52 254 tx->add(Triple(Uri(fileUrl), m_index->expand("foaf:primaryTopic"), t.a));;
Chris@46 255 Triples hashts = b->match
Chris@46 256 (Triple(t.a, m_index->expand("foaf:sha1"), Node()));
Chris@46 257 foreach (Triple hasht, hashts) {
Chris@46 258 tx->add(hasht);
Chris@46 259 }
Chris@45 260 }
Chris@46 261 } catch (std::exception &e) {
Chris@46 262 std::cerr << "Caught exception: \"" << e.what() << "\" while indexing "
Chris@46 263 << Uri(fileUrl) << ", skipping" << std::endl;
Chris@46 264 }
Chris@45 265
Chris@48 266 tx->commit();
Chris@45 267 delete tx;
Chris@44 268 }
Chris@44 269
Chris@44 270
Chris@44 271 }
Chris@44 272