xref: /glogg/src/data/logdataworkerthread.h (revision 812146a8302488475ae27a1d22ae44a1379476a9)
1 /*
2  * Copyright (C) 2009, 2010, 2014 Nicolas Bonnefon and other contributors
3  *
4  * This file is part of glogg.
5  *
6  * glogg is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * glogg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with glogg.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef LOGDATAWORKERTHREAD_H
21 #define LOGDATAWORKERTHREAD_H
22 
23 #include <QObject>
24 #include <QThread>
25 #include <QMutex>
26 #include <QWaitCondition>
27 #include <QVector>
28 
29 #include "loadingstatus.h"
30 
31 // This class is a list of end of lines position,
32 // in addition to a list of qint64 (positions within the files)
33 // it can keep track of whether the final LF was added (for non-LF terminated
34 // files) and remove it when more data are added.
35 class LinePositionArray
36 {
37   public:
38     // Default constructor
39     LinePositionArray() : array()
40     { fakeFinalLF_ = false; }
41     // Copy constructor
42     inline LinePositionArray( const LinePositionArray& orig )
43         : array(orig.array)
44     { fakeFinalLF_ = orig.fakeFinalLF_; }
45 
46     // Add a new line position at the given position
47     inline void append( qint64 pos )
48     { array.append( pos ); }
49     // Size of the array
50     inline int size()
51     { return array.size(); }
52     // Extract an element
53     inline qint64 at( int i ) const
54     { return array.at( i ); }
55     inline qint64 operator[]( int i ) const
56     { return array.at( i ); }
57     // Set the presence of a fake final LF
58     // Must be used after 'append'-ing a fake LF at the end.
59     void setFakeFinalLF( bool finalLF=true )
60     { fakeFinalLF_ = finalLF; }
61 
62     // Add another list to this one, removing any fake LF on this list.
63     LinePositionArray& operator+= ( const LinePositionArray& other )
64     {
65         // If our final LF is fake, we remove it
66         if ( fakeFinalLF_ )
67             this->array.pop_back();
68 
69         // Append the arrays
70         this->array += other.array;
71 
72         // In case the 'other' object has a fake LF
73         this->fakeFinalLF_ = other.fakeFinalLF_;
74 
75         return *this;
76     }
77 
78   private:
79     QVector<qint64> array;
80     bool fakeFinalLF_;
81 };
82 
83 // This class is a mutex protected set of indexing data.
84 // It is thread safe.
85 class IndexingData
86 {
87   public:
88     IndexingData() : dataMutex_(), linePosition_(), maxLength_(0), indexedSize_(0) { }
89 
90     // Atomically get all the indexing data
91     void getAll( qint64* size, int* length,
92             LinePositionArray* linePosition );
93 
94     // Atomically set all the indexing data
95     // (overwriting the existing)
96     void setAll( qint64 size, int length,
97             const LinePositionArray& linePosition );
98 
99     // Atomically add to all the existing
100     // indexing data.
101     void addAll( qint64 size, int length,
102             const LinePositionArray& linePosition );
103 
104   private:
105     QMutex dataMutex_;
106 
107     LinePositionArray linePosition_;
108     int maxLength_;
109     qint64 indexedSize_;
110 };
111 
112 class IndexOperation : public QObject
113 {
114   Q_OBJECT
115   public:
116     IndexOperation( QString& fileName, bool* interruptRequest );
117 
118     virtual ~IndexOperation() { }
119 
120     // Start the indexing operation, returns true if it has been done
121     // and false if it has been cancelled (results not copied)
122     virtual bool start( IndexingData& result ) = 0;
123 
124   signals:
125     void indexingProgressed( int );
126 
127   protected:
128     static const int sizeChunk;
129 
130     // Returns the total size indexed
131     qint64 doIndex( LinePositionArray& linePosition, int* maxLength,
132             qint64 initialPosition );
133 
134     QString fileName_;
135     bool* interruptRequest_;
136 };
137 
138 class FullIndexOperation : public IndexOperation
139 {
140   public:
141     FullIndexOperation( QString& fileName, bool* interruptRequest )
142         : IndexOperation( fileName, interruptRequest ) { }
143     virtual bool start( IndexingData& result );
144 };
145 
146 class PartialIndexOperation : public IndexOperation
147 {
148   public:
149     PartialIndexOperation( QString& fileName, bool* interruptRequest, qint64 position );
150     virtual bool start( IndexingData& result );
151 
152   private:
153     qint64 initialPosition_;
154 };
155 
156 // Create and manage the thread doing loading/indexing for
157 // the creating LogData. One LogDataWorkerThread is used
158 // per LogData instance.
159 // Note everything except the run() function is in the LogData's
160 // thread.
161 class LogDataWorkerThread : public QThread
162 {
163   Q_OBJECT
164 
165   public:
166     LogDataWorkerThread();
167     ~LogDataWorkerThread();
168 
169     // Attaches to a file on disk. Attaching to a non existant file
170     // will work, it will just appear as an empty file.
171     void attachFile( const QString& fileName );
172     // Instructs the thread to start a new full indexing of the file, sending
173     // signals as it progresses.
174     void indexAll();
175     // Instructs the thread to start a partial indexing (starting at
176     // the index passed).
177     void indexAdditionalLines( qint64 position );
178     // Interrupts the indexing if one is in progress
179     void interrupt();
180 
181     // Returns a copy of the current indexing data
182     void getIndexingData( qint64* indexedSize,
183             int* maxLength, LinePositionArray* linePosition );
184 
185   signals:
186     // Sent during the indexing process to signal progress
187     // percent being the percentage of completion.
188     void indexingProgressed( int percent );
189     // Sent when indexing is finished, signals the client
190     // to copy the new data back.
191     void indexingFinished( LoadingStatus status );
192 
193   protected:
194     void run();
195 
196   private:
197     void doIndexAll();
198 
199     // Mutex to protect operationRequested_ and friends
200     QMutex mutex_;
201     QWaitCondition operationRequestedCond_;
202     QWaitCondition nothingToDoCond_;
203     QString fileName_;
204 
205     // Set when the thread must die
206     bool terminate_;
207     bool interruptRequested_;
208     IndexOperation* operationRequested_;
209 
210     // Shared indexing data
211     IndexingData indexingData_;
212 };
213 
214 #endif
215