Writer.h
1 /* Copyright (C) 2020 IBM Corp.
2  * This program is Licensed under the Apache License, Version 2.0
3  * (the "License"); you may not use this file except in compliance
4  * with the License. You may obtain a copy of the License at
5  * http://www.apache.org/licenses/LICENSE-2.0
6  * Unless required by applicable law or agreed to in writing, software
7  * distributed under the License is distributed on an "AS IS" BASIS,
8  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9  * See the License for the specific language governing permissions and
10  * limitations under the License. See accompanying LICENSE file.
11  */
12 
13 #ifndef WRITER_H
14 #define WRITER_H
15 
16 #include <string>
17 #include <fstream>
18 #include <memory>
19 #include <exception>
20 
21 #include "TOC.h"
22 
23 template <typename D>
24 class Writer
25 {
26 
27 private:
28  std::shared_ptr<TOC> toc;
29  std::fstream writeStream;
30  const std::string filepath;
31 
32  void allocFile(long sizeInBytes) const
33  {
34  if (sizeInBytes < 0)
35  throw std::invalid_argument("Cannot allocate negative sized file. "
36  "Size requested is " +
37  std::to_string(sizeInBytes));
38 
39  std::ostringstream oss;
40 #if __linux__
41  oss << "fallocate -l " << sizeInBytes << " " << filepath;
42 #elif __APPLE__
43  oss << "mkfile -n " << sizeInBytes << " " << filepath;
44 #else
45  throw std::logic_error("Unsupported system (not __APPLE__ or __linux__).");
46 #endif
47 
48  // return for system is implementation dependent
49  std::system(oss.str().c_str());
50 
51  std::ifstream test(filepath, std::ios::ate);
52  long actualFileSize = test.tellg();
53  if (actualFileSize != sizeInBytes) {
54  std::ostringstream err_msg;
55  err_msg << "Could not allocate file '" << filepath
56  << "'.\nRequested size " << sizeInBytes << ", actual size "
57  << actualFileSize;
58  throw std::runtime_error(err_msg.str());
59  }
60  }
61 
62 public:
63  // A fresh writer is responsible for setting the TOC.
64  Writer(const std::string& fpath,
65  uint64_t rows,
66  uint64_t cols,
67  long recordSizeInBytes) :
68  // File needs alloc in body before stream is opened.
69  toc(std::make_shared<TOC>(rows, cols)),
70  filepath(fpath)
71  {
72  // Estimate for ctxt sizes.
73  const long tocSize = toc->memorySize();
74  const long fileSize = (cols * rows * recordSizeInBytes) + tocSize;
75  allocFile(fileSize);
76 
77  // Set the TOC
78  for (uint64_t j = 0; j < cols; ++j)
79  for (uint64_t i = 0; i < rows; ++i)
80  toc->setIdx(i, j, (i + j * rows) * recordSizeInBytes + tocSize);
81 
82  // Write it to file
83  writeStream.open(fpath, std::ios::in | std::ios::out | std::ios::binary);
84  if (!writeStream.is_open())
85  throw std::runtime_error("Could not open '" + fpath +
86  "' for writing out TOC.");
87  writeStream.seekp(0);
88  toc->write(writeStream);
89  }
90 
91  // A copied writer is not responsible for setting the TOC.
92  Writer(const Writer& other) :
93  toc(other.toc),
94  writeStream(other.filepath,
95  std::ios::in | std::ios::out | std::ios::binary),
96  filepath(other.filepath)
97  {
98  if (!writeStream.is_open())
99  throw std::runtime_error("Could not open file '" + other.filepath +
100  "' for copied Writer.");
101  }
102 
103  void writeByLocation(const D& data, uint64_t row, uint64_t col)
104  {
105  writeStream.seekp(toc->getIdx(row, col));
106  data.write(writeStream);
107  }
108 
109  TOC& getTOC() { return *toc; }
110 };
111 
112 #endif // WRITER_H
Definition: TOC.h:21
Definition: Writer.h:25
TOC & getTOC()
Definition: Writer.h:109
Writer(const std::string &fpath, uint64_t rows, uint64_t cols, long recordSizeInBytes)
Definition: Writer.h:64
void writeByLocation(const D &data, uint64_t row, uint64_t col)
Definition: Writer.h:103
Writer(const Writer &other)
Definition: Writer.h:92