Welcome to mirror list, hosted at ThFree Co, Russian Federation.

progressdispatcher.h « mirall « src - github.com/owncloud/client.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 66a8e411f7642d0830de5fe80b3711ba31125b43 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/*
 * Copyright (C) by Klaas Freitag <freitag@owncloud.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * 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 General Public License
 * for more details.
 */

#ifndef PROGRESSDISPATCHER_H
#define PROGRESSDISPATCHER_H

#include "owncloudlib.h"
#include <QObject>
#include <QHash>
#include <QTime>
#include <QQueue>
#include <QElapsedTimer>
#include "syncfileitem.h"

namespace Mirall {

/**
 * @brief The FolderScheduler class schedules folders for sync
 */
namespace Progress
{
    /** Return true is the size need to be taken in account in the total amount of time */
    inline bool isSizeDependent(csync_instructions_e instruction) {
        return instruction == CSYNC_INSTRUCTION_CONFLICT || instruction == CSYNC_INSTRUCTION_SYNC
            || instruction == CSYNC_INSTRUCTION_NEW;
    }


    struct Info {
        Info() : _totalFileCount(0), _totalSize(0), _completedFileCount(0), _completedSize(0) {}

        // Used during local and remote update phase
        QString _currentDiscoveredFolder;

        quint64 _totalFileCount;
        quint64 _totalSize;
        quint64 _completedFileCount;
        quint64 _completedSize;
        // Should this be in a separate file?
        struct EtaEstimate {
            EtaEstimate() :  _startedTime(QDateTime::currentMSecsSinceEpoch()), _agvEtaMSecs(0),_effectivProgressPerSec(0),_sampleCount(1) {}
            
            static const int MAX_AVG_DIVIDER=60;
            static const int INITAL_WAIT_TIME=5;
            
            quint64     _startedTime ;
            quint64     _agvEtaMSecs;
            quint64     _effectivProgressPerSec;
            float      _sampleCount;
            
            /**
             * reset the estiamte.
             */
            void reset() {
                _startedTime = QDateTime::currentMSecsSinceEpoch();
                _sampleCount =1;
                _effectivProgressPerSec = _agvEtaMSecs = 0;
            }
            
            /**
             * update the estimated eta time with more current data.
             * @param quint64 completed the amount the was completed.
             * @param quint64 total the total amout that should be completed.
             */
            void updateTime(quint64 completed, quint64 total) {
                quint64 elapsedTime = QDateTime::currentMSecsSinceEpoch() -  this->_startedTime ;
                //don't start until you have some good data to process, prevents jittring estiamtes at the start of the syncing process                    
                if(total != 0 && completed != 0 && elapsedTime > INITAL_WAIT_TIME ) {
                    if(_sampleCount < MAX_AVG_DIVIDER) { _sampleCount+=0.01f; }
                    // (elapsedTime-1) is an hack to avoid float "rounding" issue (ie. 0.99999999999999999999....)
                    _agvEtaMSecs = _agvEtaMSecs + (((static_cast<float>(total) / completed) * elapsedTime) - (elapsedTime-1)) - this->getEtaEstimate();
                    _effectivProgressPerSec = ( total - completed ) / (1+this->getEtaEstimate()/1000);
                }
            }
            
            /**
             * Get the eta estimate in milliseconds 
             * @return quint64 the estimate amount of milliseconds to end the process.
             */
            quint64 getEtaEstimate() const {
               return _agvEtaMSecs / _sampleCount;
           }
            
           /**
            * Get the estimated average bandwidth usage.
            * @return quint64 the estimated bandwidth usage in bytes.
            */
           quint64 getEstimatedBandwidth() const {
               return _effectivProgressPerSec;
           }
        };
        EtaEstimate _totalEtaEstimate;

        struct ProgressItem {
            ProgressItem() : _completedSize(0) {}
            SyncFileItem _item;
            quint64 _completedSize;
            EtaEstimate _etaEstimate;
        };
        QHash<QString, ProgressItem> _currentItems;
        SyncFileItem _lastCompletedItem;

        void setProgressComplete(const SyncFileItem &item) {
            _currentItems.remove(item._file);
            if (!item._isDirectory) {
                _completedFileCount++;
		        if (Progress::isSizeDependent(item._instruction)) {
		            _completedSize += item._size;
		        }
            }
            _lastCompletedItem = item;
            this->updateEstimation();
        }
        void setProgressItem(const SyncFileItem &item, quint64 size) {
            _currentItems[item._file]._item = item;
            _currentItems[item._file]._completedSize = size;
            _lastCompletedItem = SyncFileItem();
            this->updateEstimation();
            _currentItems[item._file]._etaEstimate.updateTime(size,item._size);
        }
        
        void updateEstimation() {
            if(this->_totalSize > 0) {
                _totalEtaEstimate.updateTime(this->completedSize(),this->_totalSize);
            } else {
                _totalEtaEstimate.updateTime(this->_completedFileCount,this->_totalFileCount);
            }
        }

        quint64 completedSize() const {
            quint64 r = _completedSize;
            foreach(const ProgressItem &i, _currentItems) {
                if (!i._item._isDirectory)
                    r += i._completedSize;
            }
            return r;
        }
        /**
         * Get the total completion estimate structure 
         * @return EtaEstimate a structure containing the total completion information.
         */
        EtaEstimate totalEstimate() const {
            return _totalEtaEstimate;
        }

        /**
         * Get the current file completion estimate structure 
         * @return EtaEstimate a structure containing the current file completion information.
         */
        EtaEstimate getFileEstimate(const SyncFileItem &item) const {
            return _currentItems[item._file]._etaEstimate;
        }               
    };

    OWNCLOUDSYNC_EXPORT QString asActionString( const SyncFileItem& item );
    OWNCLOUDSYNC_EXPORT QString asResultString(  const SyncFileItem& item );

    OWNCLOUDSYNC_EXPORT bool isWarningKind( SyncFileItem::Status );

}

/**
 * @file progressdispatcher.h
 * @brief A singleton class to provide sync progress information to other gui classes.
 *
 * How to use the ProgressDispatcher:
 * Just connect to the two signals either to progress for every individual file
 * or the overall sync progress.
 *
 */
class OWNCLOUDSYNC_EXPORT ProgressDispatcher : public QObject
{
    Q_OBJECT

    friend class Folder; // only allow Folder class to access the setting slots.
public:
    static ProgressDispatcher* instance();
    ~ProgressDispatcher();

signals:
    /**
      @brief Signals the progress of data transmission.

      @param[out]  folder The folder which is being processed
      @param[out]  progress   A struct with all progress info.

     */
    void progressInfo( const QString& folder, const Progress::Info& progress );
    /**
     * @brief: the item's job is completed
     */
    void jobCompleted(const QString &folder, const SyncFileItem & item);

    void syncItemDiscovered(const QString &folder, const SyncFileItem & item);

protected:
    void setProgressInfo(const QString& folder, const Progress::Info& progress);

private:
    ProgressDispatcher(QObject* parent = 0);

    QElapsedTimer _timer;
    static ProgressDispatcher* _instance;
};

}
#endif // PROGRESSDISPATCHER_H