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 @ 50:0f9353a69866

History | View | Annotate | Download (8.27 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_index = new TransactionalStore(m_bs);
37

    
38
    TypeRegistrar::addMappings(m_bs, 0);
39

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

    
47
FeatureFileIndex::~FeatureFileIndex()
48
{
49
    delete m_index;
50
    delete m_bs;
51
}
52

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

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

    
65
    return QDir(fi.filePath()).filePath("features.ttl");
66
}
67

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

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

    
80
    return fi.filePath();
81
}
82

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

    
92
    QSet<Uri> fileUris;
93

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

    
99
    fileUris.insert(tf->uri());
100

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

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

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

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

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

    
134
    bool loadedSomething = false;
135

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

    
192
    return loadedSomething;
193
}
194

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

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

    
207
    std::cerr << "Generating index..." << std::endl;
208

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

    
218
    featureDir.setFilter(QDir::Files);
219

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

    
227
    //!!! remove triples from index that refer to nonexistent files?
228

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

    
232
    std::cerr << "Done" << std::endl;
233
}
234

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

    
240
    if (m_index->contains(typeTriple)) {
241
        return;
242
    }
243

    
244
    Transaction *tx = m_index->startTransaction();
245
    tx->add(typeTriple);
246

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

    
264
    tx->commit();
265
    delete tx;
266
}
267

    
268

    
269
}
270