To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Revision:

root / common / FeatureFileIndex.cpp @ 52:e0e12bd2978d

History | View | Annotate | Download (8.39 KB)

1
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
2

    
3
#include "FeatureFileIndex.h"
4
#include "TypeRegistrar.h"
5

    
6
#include <QMutexLocker>
7
#include <QDir>
8

    
9
#include "base/TempDirectory.h"
10
#include "base/Exceptions.h"
11

    
12
using namespace Dataquay;
13

    
14

    
15
namespace ClassicalData {
16

    
17
FeatureFileIndex *
18
FeatureFileIndex::getInstance()
19
{
20
    static FeatureFileIndex instance;
21
    return &instance;
22
}
23

    
24
FeatureFileIndex::FeatureFileIndex() :
25
    m_bs(0),
26
    m_index(0)
27
{
28
    try {
29
        m_indexFileName = getIndexFileName();
30
    } catch (DirectoryCreationFailed f) {
31
        std::cerr << "FeatureFileIndex: ERROR: Failed to find or create index directory: " << f.what() << std::endl;
32
        return;
33
    }
34

    
35
    m_bs = new BasicStore;
36
    m_bs->setBaseUri(Uri(QUrl::fromLocalFile(m_indexFileName)));
37

    
38
    m_index = new TransactionalStore(m_bs);
39

    
40
    TypeRegistrar::addMappings(m_bs, 0);
41

    
42
    if (QFile(m_indexFileName).exists()) {
43
        m_bs->import(QUrl::fromLocalFile(m_indexFileName),
44
                     BasicStore::ImportIgnoreDuplicates);
45
        //!!! catch
46
    }
47
}
48

    
49
FeatureFileIndex::~FeatureFileIndex()
50
{
51
    delete m_index;
52
    delete m_bs;
53
}
54

    
55
QString
56
FeatureFileIndex::getIndexFileName()
57
{
58
    QDir d = TempDirectory::getInstance()->getContainingPath();
59
    QString n("index");
60
    QFileInfo fi(d.filePath(n));
61

    
62
    if ((fi.exists() && !fi.isDir()) ||
63
        (!fi.exists() && !d.mkdir(n))) {
64
        throw DirectoryCreationFailed(fi.filePath());
65
    }
66

    
67
    return QDir(fi.filePath()).filePath("features.ttl");
68
}
69

    
70
QString
71
FeatureFileIndex::getFeatureDirectoryName()
72
{
73
    QDir d = TempDirectory::getInstance()->getContainingPath();
74
    QString n("features");
75
    QFileInfo fi(d.filePath(n));
76

    
77
    if ((fi.exists() && !fi.isDir()) ||
78
        (!fi.exists() && !d.mkdir(n))) {
79
        throw DirectoryCreationFailed(fi.filePath());
80
    }
81

    
82
    return fi.filePath();
83
}
84

    
85
void
86
FeatureFileIndex::loadFor(AudioFile *tf, Store *store)
87
{
88
    if (!m_index) {
89
        std::cerr << "FeatureFileIndex::loadFor: No index!" << std::endl;
90
        return;
91
    }
92
    updateIndex();
93

    
94
    QSet<Uri> fileUris;
95

    
96
    // The same file may be referred to with more than one URI; we
97
    // want to load any or all of: the URI in our file object; encoded
98
    // version of same; and any other file that is recorded as having
99
    // the same hash (i.e. it is the same file).
100

    
101
    fileUris.insert(tf->uri());
102

    
103
    // and again with encoded version of file URI
104
    QByteArray enc = QUrl(tf->uri().toString()).toEncoded();
105
    fileUris.insert(Uri(QString::fromUtf8(enc)));
106

    
107
    // and again with anything else having the same hash
108
    if (tf->hash() != "") {
109
        Triple pattern(Node(), store->expand("foaf:sha1"), Node(tf->hash()));
110
        Triples results = m_index->match(pattern);
111
        std::cerr << "FeatureFileIndex::loadFor: " << results.size() << " audio file(s) found with hash " << tf->hash().toStdString() << std::endl;
112
        foreach (Triple t, results) {
113
            fileUris.insert(Uri(t.a.value));
114
        }
115
    }
116

    
117
    foreach (Uri u, fileUris) {
118
        loadFor(tf->uri(), u, tf->hash(), store);
119
    }
120
}
121

    
122
bool
123
FeatureFileIndex::loadFor(Uri canonicalUri, Uri afuri,
124
                          QString hash, Store *store)
125
{
126
    // The AudioFile object has a URI and a hash.  Feature files
127
    // generated for this AudioFile should ideally have a matching
128
    // hash; if they have no hash, then the URI should match.  If the
129
    // hash is present in the feature file but does not match, then it
130
    // cannot be the right track even if the URI matches.
131

    
132
    Triple pattern(Node(), store->expand("foaf:primaryTopic"), afuri);
133
    Triples results = m_index->match(pattern);
134
    std::cerr << "FeatureFileIndex::loadFor: " << results.size() << " feature file(s) for audio file " << afuri << std::endl;
135

    
136
    bool loadedSomething = false;
137

    
138
    foreach (Triple t, results) {
139
        try {
140
            BasicStore *b = BasicStore::load(QUrl(t.a.value));
141
            Triples ts = b->match
142
                (Triple(afuri, store->expand("a"), m_index->expand("mo:AudioFile")));
143
            std::cerr << "FeatureFileIndex::loadFor: feature file "
144
                      << t.a << " has " << ts.size() << " type node(s) for this audio file" << std::endl;
145
            bool someGood = false;
146
            foreach (Triple t, ts) {
147
                bool good = true;
148
                if (hash != "") {
149
                    Triples hashts = b->match
150
                        (Triple(afuri, m_index->expand("foaf:sha1"), Node()));
151
                    std::cerr << "FeatureFileIndex::loadFor: feature file "
152
                              << t.a << " has " << hashts.size() << " hashes for this file" << std::endl;
153
                    if (!hashts.empty()) {
154
                        good = false;
155
                        foreach (Triple hasht, hashts) {
156
                            if (hasht.c.value == hash) {
157
                                std::cerr << "Hash " << hasht.c << " matches our hash " << hash.toStdString() << std::endl;
158
                                good = true;
159
                                break;
160
                            }
161
                        }
162
                        if (!good) {
163
                            std::cerr << "(no hash matches, eliminating file)" << std::endl;
164
                        }
165
                    } else {
166
                        std::cerr << "(so cannot eliminate file via hash)" << std::endl;
167
                    }
168
                }
169
                if (good) {
170
                    std::cerr << "...going to import this one" << std::endl;
171
                    someGood = true;
172
                }
173
            }
174
            if (someGood) {
175
                Triples all = b->match(Triple());
176
                std::cerr << "Importing " << all.size() << " triple(s) into store" << std::endl;
177
                // Replace instances of the audio file URI with our
178
                // canonical URI (we want to make sure we're
179
                // associating these facts with our own URI for this
180
                // file, even if they originated from a different URI
181
                // with the same hash)
182
                Node from = Node(Uri(afuri.toString()));
183
                Node to = Node(Uri(canonicalUri.toString()));
184
                foreach (Triple t, all) {
185
                    if (t.a == from) t.a = to;
186
                    if (t.c == from) t.c = to;
187
                    store->add(t);
188
                }
189
                loadedSomething = true;
190
            }
191
        } catch (...) { }
192
    }
193

    
194
    return loadedSomething;
195
}
196

    
197
void
198
FeatureFileIndex::featureFileAdded(QString filepath)
199
{
200
    index(QUrl::fromLocalFile(filepath));
201
}    
202

    
203
void
204
FeatureFileIndex::updateIndex()
205
{
206
    QMutexLocker locker(&m_mutex);
207
    if (!m_index) return;
208

    
209
    std::cerr << "Generating index..." << std::endl;
210

    
211
    QDir featureDir;
212
    try {
213
        QString s = getFeatureDirectoryName();
214
        featureDir = QDir(s);
215
    } catch (DirectoryCreationFailed f) {
216
        std::cerr << "FeatureFileIndex::updateIndex: ERROR: Failed to find or create feature directory: " << f.what() << std::endl;
217
        return;
218
    }
219

    
220
    featureDir.setFilter(QDir::Files);
221

    
222
    for (unsigned int i = 0; i < featureDir.count(); ++i) {
223
        QFileInfo fi(featureDir.filePath(featureDir[i]));
224
        if (fi.isFile() && fi.isReadable()) {
225
            index(QUrl::fromLocalFile(fi.filePath()));
226
        }
227
    }
228

    
229
    //!!! remove triples from index that refer to nonexistent files?
230

    
231
    std::cerr << "Saving index to " << m_indexFileName.toStdString() << std::endl;
232
    m_bs->save(m_indexFileName);
233

    
234
    std::cerr << "Done" << std::endl;
235
}
236

    
237
void
238
FeatureFileIndex::index(QUrl fileUrl)
239
{
240
    Triple typeTriple(Uri(fileUrl), m_index->expand("a"), m_index->expand("foaf:Document"));
241

    
242
    if (m_index->contains(typeTriple)) {
243
        return;
244
    }
245

    
246
    Transaction *tx = m_index->startTransaction();
247
    tx->add(typeTriple);
248

    
249
    try {
250
        BasicStore *b = BasicStore::load(fileUrl);
251
        Triples ts = b->match
252
            (Triple(Node(), m_index->expand("a"), m_index->expand("mo:AudioFile")));
253
        foreach (Triple t, ts) {
254
            tx->add(Triple(Uri(fileUrl), m_index->expand("foaf:primaryTopic"), t.a));;
255
            Triples hashts = b->match
256
                (Triple(t.a, m_index->expand("foaf:sha1"), Node()));
257
            foreach (Triple hasht, hashts) {
258
                tx->add(hasht);
259
            }
260
        }
261
    } catch (std::exception &e) {
262
        std::cerr << "Caught exception: \"" << e.what() << "\" while indexing "
263
                  << Uri(fileUrl) << ", skipping" << std::endl;
264
    }
265

    
266
    tx->commit();
267
    delete tx;
268
}
269

    
270

    
271
}
272