ICP  1
SplitFile.cpp
Go to the documentation of this file.
1 #include "stdafx.h"
2 #include "SplitFile.h"
3 #include "icputils.h"
4 
5 const size_t SplitFile::m_bytes_per_file = 512*1024;
6 const size_t SplitFile::m_files_per_sub_dir = 1000;
7 
8 SplitFile::SplitFile() : m_file(NULL), m_count(0), m_shflag(_SH_DENYNO), m_toggle_readonly(false), m_current_bytes(0), m_mode(IFile::ReadOnly)
9 {
10  setLoggerName("SplitFile");
11 }
12 
14 {
15  close();
16 }
17 
18 int SplitFile::open(const std::string& path, Mode mode, int shflag, bool toggle_readonly)
19 {
20  m_toggle_readonly = toggle_readonly;
21  m_shflag = shflag;
22  m_mode = mode;
23  m_top_directory = Poco::Path::forDirectory(path);
24  m_count = 0;
25  return open();
26 }
27 
29 {
30  m_current_bytes = 0;
31  std::string file_name = getFileName();
32  Poco::Path p(file_name);
33  p.setFileName("");
34  Poco::File f(p);
35  f.createDirectories();
36  if (m_toggle_readonly && (_access(file_name.c_str(), 0) == 0) )
37  {
38  RetryWIN32APIBOOL(boost::bind(SetFileAttributes, file_name.c_str(), FILE_ATTRIBUTE_NORMAL), 10); // clear read-only
39  }
40  std::string fmode = openMode(file_name);
41  for(int nretry = 10; ((m_file = _fsopen(file_name.c_str(), fmode.c_str(), m_shflag)) == NULL) && (nretry > 0); --nretry)
42  {
43  LOGSTR_ERROR(file_name + " in mode " + fmode + ": " + strerror(errno));
44  Sleep(100);
45  }
46  if (m_file != NULL)
47  {
48  return 0;
49  }
50  else
51  {
52  return -1;
53  }
54 }
55 
56 size_t SplitFile::write(const void* data, size_t element_size, size_t nelement)
57 {
58  if (m_file == NULL)
59  {
60  return static_cast<size_t>(-1);
61  }
62  size_t n = m_current_bytes + nelement*element_size;
63  if (n <= m_bytes_per_file)
64  {
65  m_current_bytes = n;
66  return fwrite(data, element_size, nelement, m_file);
67  }
68  size_t n1 = (m_bytes_per_file - m_current_bytes) / element_size;
69  if (fwrite(data, element_size, n1, m_file) != n1)
70  {
71  return static_cast<size_t>(-1);
72  }
73  nextFile();
74  n = write((const char*)data + n1 * element_size, element_size, nelement - n1);
75  if (n != -1)
76  {
77  return n1 + n;
78  }
79  else
80  {
81  return static_cast<size_t>(-1);
82  }
83 }
84 
85 size_t SplitFile::read(void* data, size_t element_size, size_t nelement)
86 {
87  if (m_file == NULL)
88  {
89  return static_cast<size_t>(-1);
90  }
91  if (nelement == 0)
92  {
93  return 0;
94  }
95  size_t n = m_current_bytes + nelement*element_size;
96  if (n <= m_bytes_per_file)
97  {
98  m_current_bytes = n;
99  return fread(data, element_size, nelement, m_file);
100  }
101  size_t n1 = (m_bytes_per_file - m_current_bytes) / element_size;
102  if ( (n = fread(data, element_size, n1, m_file)) != n1 )
103  {
104  if (n != static_cast<size_t>(-1))
105  {
106  m_current_bytes += n * element_size;
107  }
108  return n;
109  }
110  nextFile();
111  n = read((char*)data + n1 * element_size, element_size, nelement - n1);
112  if ( n != static_cast<size_t>(-1) )
113  {
114  return n1 + n;
115  }
116  else
117  {
118  return static_cast<size_t>(-1);
119  }
120 }
121 
123 {
124  if (close() != 0)
125  {
126  throw std::runtime_error("close");
127  }
128  ++m_count;
129  if (open() != 0)
130  {
131  throw std::runtime_error("open");
132  }
133 }
134 
136 {
137  int ret = 0;
138  if (m_file != NULL)
139  {
140  if (flush() != 0)
141  {
142  throw std::runtime_error("flush");
143  }
144  ret = fclose(m_file);
145  m_file = NULL;
146  if (m_toggle_readonly)
147  {
148  RetryWIN32APIBOOL(boost::bind(SetFileAttributes, getFileName().c_str(), FILE_ATTRIBUTE_READONLY), 10); // set read-only file attribute
149  }
150  }
151  return ret;
152 }
153 
154 int SplitFile::seek(int64_t offset, int whence)
155 {
156  if (whence != SEEK_SET)
157  {
158  throw std::runtime_error("SplitFile::seek");
159  }
160  size_t count = countFromOffset(offset);
161  if (count != m_count || m_file == NULL)
162  {
163  if (close() != 0)
164  {
165  throw std::runtime_error("close");
166  }
167  m_count = count;
168  if (open() != 0)
169  {
170  throw std::runtime_error("open");
171  }
172  }
173 // LOGSTR_INFORMATION("Seeking to " << offset << " bytes which is count=" << m_count << " offset=" << offset % m_bytes_per_file);
175  return fseek(m_file, m_current_bytes, whence);
176 }
177 
178 int SplitFile::tell(int64_t& offset)
179 {
180  offset = static_cast<uint64_t>(m_count) * m_bytes_per_file + m_current_bytes;
181  if (ftell(m_file) != m_current_bytes)
182  {
183  throw std::runtime_error("ftell");
184  }
185  return 0;
186 }
187 
189 {
190  std::set<std::string> files;
191  findFiles(files);
192  std::string current_file = getFileName();
193  BOOST_FOREACH(const std::string& s, files)
194  {
195  if (s != current_file)
196  {
197  RetryWIN32APIBOOL(boost::bind(SetFileAttributes, s.c_str(), FILE_ATTRIBUTE_NORMAL), 10); // clear read-only file attribute
198  std::remove(s.c_str());
199  }
200  }
201  if (m_file != NULL)
202  {
203  return _chsize(fileno(m_file), 0);
204  }
205  else
206  {
207  std::remove(current_file.c_str());
208  return 0;
209  }
210 }
211 
212 void SplitFile::removeFile(const std::string& path)
213 {
214  std::set<std::string> files;
215  findFiles(Poco::Path::forDirectory(path), files);
216  BOOST_FOREACH(const std::string& s, files)
217  {
218  RetryWIN32APIBOOL(boost::bind(SetFileAttributes, s.c_str(), FILE_ATTRIBUTE_NORMAL), 10); // clear read-only file attribute
219  std::remove(s.c_str());
220  }
221  // remove directories
222  Poco::File f(path);
223  try
224  {
225  f.remove(true);
226  }
227  catch(const std::exception& )
228  {
229  ; // LOGSTR_INFORMATION("Cannot delete " + path + ": " + ex.what());
230  }
231 }
232 
233 bool SplitFile::isOpen() const
234 {
235  return m_file != NULL;
236 }
237 
239 {
240  if (m_file != NULL)
241  {
242  return fflush(m_file);
243  }
244  else
245  {
246  return 0;
247  }
248 }
249 
250 size_t SplitFile::countFromOffset(int64_t offset) const
251 {
252  return offset / m_bytes_per_file;
253 }
254 
255 std::string SplitFile::getFileName() const
256 {
257  return fileNamefromCount(m_count);
258 }
259 
260 std::string SplitFile::fileNamefromCount(size_t count) const
261 {
262  Poco::Path p(m_top_directory, Poco::format("F%lu.tmp", (unsigned long)(count % m_files_per_sub_dir)));
263  p.pushDirectory(Poco::format("D%lu", (unsigned long)(count / m_files_per_sub_dir)));
264  return p.toString();
265 }
266 
267 void SplitFile::findFiles(std::set<std::string>& files) const
268 {
269  findFiles(m_top_directory, files);
270 }
271 
272 void SplitFile::findFiles(const Poco::Path& path, std::set<std::string>& files)
273 {
274  files.clear();
275  std::string file_expr("F[0-9]*.tmp"); // poco glob is shell like not RE like
276  Poco::Path search_expr(path, file_expr);
277  search_expr.pushDirectory("D[0-9]*"); // poco glob is shell like not RE like
278  Poco::Glob::glob(search_expr, files, Poco::Glob::GLOB_CASELESS);
279 }
280 
282 std::string SplitFile::openMode(const std::string& path) const
283 {
284  std::string fmode;
285  // "N" is to mark the handle as noinherit so it does not get propagated to spawned processes
286  if (m_mode == IFile::ReadOnly)
287  {
288  fmode = "rbN";
289  }
290  else if (m_mode == IFile::ReadWriteCreate)
291  {
292  if (_access(path.c_str(), 0) == 0)
293  {
294  fmode = "r+bcN";
295  }
296  else
297  {
298  fmode = "wbcN";
299  }
300  }
301  return fmode;
302 }
int tell(int64_t &offset)
Definition: SplitFile.cpp:178
int seek(int64_t offset, int whence)
Definition: SplitFile.cpp:154
size_t write(const void *data, size_t element_size, size_t nelement)
Definition: SplitFile.cpp:56
size_t countFromOffset(int64_t offset) const
Definition: SplitFile.cpp:250
FILE * m_file
Definition: SplitFile.h:9
Poco::Path m_top_directory
Definition: SplitFile.h:17
static void RetryWIN32APIBOOL(boost::function< BOOL()> func, int nretry)
Definition: icputils.h:97
size_t m_count
Definition: SplitFile.h:10
int flush()
Definition: SplitFile.cpp:238
int close()
Definition: SplitFile.cpp:135
std::string fileNamefromCount(size_t count) const
Definition: SplitFile.cpp:260
int m_shflag
Definition: SplitFile.h:15
int m_mode
Definition: SplitFile.h:16
static const size_t m_files_per_sub_dir
Definition: SplitFile.h:13
int open()
Definition: SplitFile.cpp:28
void nextFile()
Definition: SplitFile.cpp:122
size_t read(void *data, size_t element_size, size_t nelement)
Definition: SplitFile.cpp:85
void findFiles(std::set< std::string > &files) const
Definition: SplitFile.cpp:267
size_t m_current_bytes
Definition: SplitFile.h:11
std::string openMode(const std::string &path) const
determine flags to use for fopen/fsopen
Definition: SplitFile.cpp:282
#define LOGSTR_ERROR(__arg)
Definition: IsisBase.h:99
static void removeFile(const std::string &path)
Definition: SplitFile.cpp:212
bool m_toggle_readonly
Definition: SplitFile.h:18
void setLoggerName(const std::string &logger_name)
Definition: IsisBase.h:17
static const size_t m_bytes_per_file
Definition: SplitFile.h:12
int discardContents()
Definition: SplitFile.cpp:188
std::string getFileName() const
Definition: SplitFile.cpp:255
bool isOpen() const
Definition: SplitFile.cpp:233