Parser.cpp 4.94 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015 Hugo Beauzée-Luyssen, Videolabs
 *
 * Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

23
24
25
26
#if HAVE_CONFIG_H
# include "config.h"
#endif

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
27
28
#include "Parser.h"

29
#include <algorithm>
30
#include <utility>
31

32
#include "medialibrary/IMediaLibrary.h"
33
34
#include "Media.h"
#include "File.h"
35
#include "ParserWorker.h"
36

37
38
39
namespace medialibrary
{

40
Parser::Parser( MediaLibrary* ml )
41
42
    : m_ml( ml )
    , m_callback( ml->getCb() )
43
44
45
    , m_opToDo( 0 )
    , m_opDone( 0 )
    , m_percent( 0 )
46
47
48
{
}

49
50
Parser::~Parser()
{
51
    stop();
52
53
}

54
void Parser::addService( ServicePtr service )
55
{
56
    auto worker = std::make_unique<ParserWorker>();
57
58
    if ( worker->initialize( m_ml, this, std::move( service ) ) == false )
        return;
59
    m_services.push_back( std::move( worker ) );
60
61
}

62
void Parser::parse( std::shared_ptr<parser::Task> task )
63
{
64
    if ( m_services.empty() == true )
65
        return;
66
    m_services[0]->parse( std::move( task ) );
67
68
69
70
    m_opToDo += m_services.size();
    updateStats();
}

71
72
void Parser::start()
{
73
    restore();
74
75
}

76
77
void Parser::pause()
{
78
79
    for ( auto& s : m_services )
        s->pause();
80
81
82
83
}

void Parser::resume()
{
84
85
    for ( auto& s : m_services )
        s->resume();
86
87
}

88
89
90
91
92
93
94
95
96
97
98
99
void Parser::stop()
{
    for ( auto& s : m_services )
    {
        s->signalStop();
    }
    for ( auto& s : m_services )
    {
        s->stop();
    }
}

100
101
102
103
104
105
void Parser::flush()
{
    for ( auto& s : m_services )
        s->flush();
}

106
107
108
109
110
111
void Parser::restart()
{
    for ( auto& s : m_services )
        s->restart();
}

112
113
void Parser::restore()
{
114
115
116
    if ( m_services.empty() == true )
        return;

117
    auto tasks = parser::Task::fetchUncompleted( m_ml );
118
119
    LOG_INFO( "Resuming parsing on ", tasks.size(), " tasks" );
    for ( auto& t : tasks )
120
    {
121
122
        if ( t->restoreLinkedEntities() == false )
            continue;
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
123
        parse( std::move( t ) );
124
125
126
    }
}

127
void Parser::updateStats()
128
{
129
130
    if ( m_opDone == 0 && m_opToDo > 0 && m_chrono == decltype(m_chrono){})
        m_chrono = std::chrono::steady_clock::now();
131
132
    auto percent = m_opToDo > 0 ? ( m_opDone * 100 / m_opToDo ) : 0;
    if ( percent != m_percent )
133
    {
134
        m_percent = percent;
135
        LOG_INFO( "Updating progress: ", percent );
136
        m_callback->onParsingStatsUpdated( m_percent );
137
138
139
140
        if ( m_percent == 100 )
        {
            auto duration = std::chrono::steady_clock::now() - m_chrono;
            LOG_DEBUG( "Finished all parsing operations in ",
141
                       std::chrono::duration_cast<std::chrono::milliseconds>( duration ).count(), "ms" );
142
143
            m_chrono = decltype(m_chrono){};
        }
144
145
146
    }
}

147
void Parser::done( std::shared_ptr<parser::Task> t, parser::Task::Status status )
148
{
149
    ++m_opDone;
150
151

    auto serviceIdx = ++t->currentService;
152

153
    if ( status == parser::Task::Status::TemporaryUnavailable ||
154
         status == parser::Task::Status::Fatal || t->isCompleted() )
155
    {
156
157
158
159
160
        if ( serviceIdx < m_services.size() )
        {
            // We won't process the next tasks, so we need to keep the number of "todo" operations coherent:
            m_opToDo -= m_services.size() - serviceIdx;
        }
161
        updateStats();
162
        return;
163
    }
164

165
    // If some services declined to parse the file, start over again.
166
    assert( serviceIdx < m_services.size() );
167
    updateStats();
168
    m_services[serviceIdx]->parse( std::move( t ) );
169
}
170

171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
void Parser::onIdleChanged( bool idle )
{
    // If any parser service is not idle, then the global parser state is active
    if ( idle == false )
    {
        m_ml->onParserIdleChanged( false );
        return;
    }
    // Otherwise the parser is idle when all services are idle
    for ( const auto& s : m_services )
    {
        // We're switching a service from "not idle" to "idle" here, so as far as the medialibrary
        // is concerned the parser is still "not idle". In case a single parser service isn't
        // idle, no need to trigger a change to the medialibrary.
        if ( s->isIdle() == false )
            return;
    }
    m_ml->onParserIdleChanged( true );
}

191
}