root/trunk/whisperlib/common/io/logio/logio.h

Revision 7, 8.1 kB (checked in by whispercastorg, 2 years ago)

version 0.2.0

Line 
1 // Copyright (c) 2009, Whispersoft s.r.l.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Whispersoft s.r.l. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Author: Catalin Popescu
31
32 // Logging interface - one for write and one for read .
33 //
34 // Logs are composed from files of (approximately) fixed length,
35 // sequentialy numbered. These file are composed from fixed sized
36 // blocks of variable length records.
37 //
38 // The position in a log is a tripet: (file_num, block_num, record_num)
39 //
40
41 #ifndef __COMMON_IO_LOGIO_LOGIO_H__
42 #define __COMMON_IO_LOGIO_LOGIO_H__
43
44 #include <string>
45 #include <whisperlib/common/base/types.h>
46 #include <whisperlib/common/io/buffer/memory_stream.h>
47 #include <whisperlib/common/io/logio/recordio.h>
48 #include <whisperlib/common/base/re.h>
49
50 namespace io {
51
52 static const int32 kDefaultBlocksPerFile = 1 << 14;
53
54 //////////////////////////////////////////////////////////////////////
55
56 struct LogPos {
57   int32 file_num_;
58   int32 block_num_;
59   int32 record_num_;
60   LogPos()
61     : file_num_(-1), block_num_(-1), record_num_(-1) {
62   }
63   LogPos(int32 file_num, int32 block_num, int32 record_num)
64     : file_num_(file_num), block_num_(block_num), record_num_(record_num) {
65   }
66   LogPos(const LogPos& l)
67     : file_num_(l.file_num_),
68       block_num_(l.block_num_),
69       record_num_(l.record_num_) {
70   };
71
72   const LogPos& operator=(const LogPos& l) {
73     file_num_ = l.file_num_;
74     block_num_ = l.block_num_;
75     record_num_ = l.record_num_;
76     return *this;
77   }
78   bool IsNull() const {
79     return file_num_ == -1;
80   }
81   string ToString() const {
82     return strutil::StringPrintf(
83       " LogPos(file#: %5d; block#: %5d; record#: %5d)",
84       static_cast<int32>(file_num_),
85       static_cast<int32>(block_num_),
86       static_cast<int32>(record_num_));
87   }
88   bool operator==(const LogPos& l) const {
89     return (file_num_ == l.file_num_ &&
90             block_num_ == l.block_num_ &&
91             record_num_ == l.record_num_);
92   }
93 };
94
95 //////////////////////////////////////////////////////////////////////
96
97 class LogWriter {
98  public:
99   LogWriter(const char* log_dir,
100             const char* file_base,
101             bool sync_on_write,
102             int32 block_size = kDefaultRecordBlockSize,
103             int32 blocks_per_file = kDefaultBlocksPerFile,
104             bool temporary_incomplete_file = false,
105             bool deflate = false);
106   ~LogWriter();
107
108   bool WriteRecord(io::MemoryStream* in,
109                    bool force_flush = false);
110   bool WriteRecord(const char* buffer, int32 size,
111                    bool force_flush = false);
112
113   bool Flush();
114
115   const string& file_name() const { return file_name_; }
116
117   // This makes sense after a Flush() call
118   LogPos Tell() const;
119
120  private:
121   // Flushes the buffer after appending a record in the recorder
122   bool ProcessWriteRecord(bool result, bool force_flush);
123   // Name of the current file to open (according to our internal members)
124   // If temp == true and the real file does not exist:
125   //   => generates a temporary filename
126   // else => returns the real file name
127   string ComposeFileName(bool temp) const;
128   // Puts the current buf_ into the log file
129   bool WriteBuffer(bool force_flush);
130   // Determines and opens the next log file
131   bool OpenLog();
132   // Close the current log file. Moves temporary file in final place.
133   void CloseLog();
134   // Makes the file size correct for the current log file
135   bool NormalizeFileSize(int64 pos);
136
137   const string log_dir_;         // log files are here..
138   const string file_base_;       // and begin w/ this name
139   const bool   sync_on_write_;   // we synch th files
140   re::RE       re_;              // matches log files
141   const int64  max_file_size_;   // we stop at logs files of this size
142                                  // (and continue to the next file)
143   const int32 block_size_;       // we create block of records of this size
144   const int32 blocks_per_file_;  // and we write these many blocks per file
145   const bool temporary_incomplete_file_;
146                                  // incomplete files have a temporary name.
147                                  // Once a file is complete it is moved in
148                                  // the right place.
149   const bool deflate_;           // deflate records on writing
150                                  // (makes sense for txt)
151
152   int32 file_num_;               // the current file number
153                                  //  (for the opened file)
154   int   fd_;                     // current file descriptor
155   string file_name_;             // name for the current file
156   MemoryStream buf_;             // used to accumulate records
157   RecordWriter recorder_;        // encapsulates records for us
158
159
160   DISALLOW_EVIL_CONSTRUCTORS(LogWriter);
161 };
162
163 //////////////////////////////////////////////////////////////////////
164
165 class LogReader {
166  public:
167   LogReader(const char* log_dir,
168             const char* file_base,
169             int32 block_size = kDefaultRecordBlockSize,
170             int32 blocks_per_file = kDefaultBlocksPerFile);
171   ~LogReader();
172
173   bool GetNextRecord(io::MemoryStream* out);
174
175   int32 num_errors() const   { return num_errors_; }
176   int   last_errno() const   { return last_errno_; }
177
178   const string& file_name() const { return file_name_; }
179
180   const LogPos& Tell() const { return last_read_pos_;    }
181   const LogPos& crt_pos() const { return crt_pos_;    }
182   bool Seek(const LogPos& log_pos);
183
184   bool IsValid() const {
185     return fd_ != INVALID_FD_VALUE;
186   }
187   void Close() {
188     CloseInternal(false);
189   }
190   bool Rewind();
191
192   string ComposeFileName(int32 file_num) const;
193
194  private:
195   void CloseInternal(bool is_error);
196   bool OpenFile(int32 file_num);
197   bool AdvanceToPosInFile(const LogPos& log_pos);
198   bool ReadNextBlock();
199
200
201   const string log_dir_;         // log files are here..
202   const string file_base_;       // and begin w/ this name
203   re::RE       re_;              // matches log files
204   const int32 block_size_;       // we create block of records of this size
205   const int32 blocks_per_file_;  // and we write these many blocks per file
206
207   int   fd_;                     // current file descriptor
208   string file_name_;             // the name of the current file
209   LogPos crt_pos_;               // our position in log
210   LogPos last_read_pos_;         // our position in log - w/
211                                  // a valid block to read
212   RecordReader reader_;          // splits records for us
213   int32 num_errors_;
214   int32 last_errno_;
215   io::MemoryStream buf_;
216
217   DISALLOW_EVIL_CONSTRUCTORS(LogReader);
218 };
219
220 // Clean log files before the given position (i.e. you can seek to the
221 // given position, but probably not before .. )
222 //
223 // We return how many files we have deleted.
224 int32 CleanLog(const char* log_dir, const char* file_base, LogPos first_pos,
225                int32 block_size = kDefaultRecordBlockSize);
226 }
227
228 #endif  // __COMMON_IO_LOGIO_LOGIO_H__
Note: See TracBrowser for help on using the browser.