AMPS C/C++ Client Class Reference
AMPS C/C++ Client Version 5.3.4.3
MMapStoreBuffer.hpp
Go to the documentation of this file.
1 //
3 // Copyright (c) 2010-2024 60East Technologies Inc., All Rights Reserved.
4 //
5 // This computer software is owned by 60East Technologies Inc. and is
6 // protected by U.S. copyright laws and other laws and by international
7 // treaties. This computer software is furnished by 60East Technologies
8 // Inc. pursuant to a written license agreement and may be used, copied,
9 // transmitted, and stored only in accordance with the terms of such
10 // license agreement and with the inclusion of the above copyright notice.
11 // This computer software or any other copies thereof may not be provided
12 // or otherwise made available to any other person.
13 //
14 // U.S. Government Restricted Rights. This computer software: (a) was
15 // developed at private expense and is in all respects the proprietary
16 // information of 60East Technologies Inc.; (b) was not developed with
17 // government funds; (c) is a trade secret of 60East Technologies Inc.
18 // for all purposes of the Freedom of Information Act; and (d) is a
19 // commercial item and thus, pursuant to Section 12.212 of the Federal
20 // Acquisition Regulations (FAR) and DFAR Supplement Section 227.7202,
21 // Government's use, duplication or disclosure of the computer software
22 // is subject to the restrictions set forth by 60East Technologies Inc..
23 //
25 
26 #ifndef _MMAPSTOREBUFFER_H_
27 #define _MMAPSTOREBUFFER_H_
28 
29 #include <amps/ampsplusplus.hpp>
31 #include <string>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #ifdef _WIN32
36  #include <windows.h>
37 #else
38  #include <sys/mman.h>
39 #endif
40 
43 
44 
45 namespace AMPS
46 {
50  {
51  public:
57  MMapStoreBuffer(const std::string& fileName_)
59 #ifdef _WIN32
60  , _mapFile(INVALID_HANDLE_VALUE), _file(INVALID_HANDLE_VALUE)
61  {
62  _file = CreateFileA(fileName_.c_str(), GENERIC_READ | GENERIC_WRITE, 0,
63  NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
64  if ( _file == INVALID_HANDLE_VALUE )
65  {
66  std::ostringstream os;
67  os << "Failed to create file " << fileName_ << " for MMapStoreBuffer";
68  error(os.str());
69  }
70  LARGE_INTEGER liFileSize;
71  if (GetFileSizeEx(_file, &liFileSize) == 0)
72  {
73  std::ostringstream os;
74  os << "Failure getting file size of " << fileName_ << " for MMapStoreBuffer";
75  error(os.str());
76  }
77 #ifdef _WIN64
78  size_t fileSize = liFileSize.QuadPart;
79 #else
80  size_t fileSize = liFileSize.LowPart;
81 #endif
82  _setSize(AMPS_MEMORYBUFFER_DEFAULT_LENGTH > fileSize
83  ? AMPS_MEMORYBUFFER_DEFAULT_LENGTH : fileSize);
84 #else
85  {
86  _fd = ::open(fileName_.c_str(), O_CREAT | O_RDWR, (mode_t)0644);
87  struct stat statBuf;
88  memset(&statBuf, 0, sizeof(statBuf));
89  if (fstat(_fd, &statBuf) == -1)
90  {
91  std::ostringstream os;
92  os << "Failed to stat file " << fileName_ << " for MMapStoreBuffer";
93  error(os.str());
94  }
95  bool recovery = statBuf.st_size >= (ssize_t)AMPS_MEMORYBUFFER_DEFAULT_LENGTH;
96  _setSize(recovery ? (size_t)statBuf.st_size
97  : AMPS_MEMORYBUFFER_DEFAULT_LENGTH,
98  recovery);
99 #endif
100  }
101 
102  ~MMapStoreBuffer()
103  {
104  if (_buffer)
105  {
106  close();
107  }
108  }
109 
110  void close()
111  {
112  sync();
113 #ifdef _WIN32
114  FlushFileBuffers(_file);
115  UnmapViewOfFile(_buffer);
116  CloseHandle(_mapFile);
117  CloseHandle(_file);
118  _mapFile = INVALID_HANDLE_VALUE;
119  _file = INVALID_HANDLE_VALUE;
120 #else
121  munmap(_buffer, _bufferLen);
122  ::close(_fd);
123  _fd = 0;
124 #endif
125  _buffer = NULL;
126  _bufferLen = 0;
127  }
128 
129  void sync()
130  {
131  if (_buffer != NULL && _bufferLen)
132  {
133 #ifdef _WIN32
134  if (!FlushViewOfFile(_buffer, _bufferPos))
135 #else
136  if (msync(_buffer, _bufferPos, MS_ASYNC) != 0)
137 #endif
138  {
139  std::ostringstream os;
140  os << "Failed to sync mapped memory; buffer: " << (size_t)_buffer
141  << " pos: " << _bufferPos;
142  error(os.str());
143  }
144  }
145  }
146 
147  virtual void setSize(size_t newSize_)
148  {
149  _setSize(newSize_);
150  }
151 
152  void _setSize(size_t newSize_, bool recovery_ = false)
153  {
154  if (_bufferLen > 0)
155  {
156  sync();
157  }
158  // Make sure we're using a multiple of page size
159  size_t sz = newSize_ & (size_t)(~(getPageSize() - 1));
160  if (sz < newSize_)
161  {
162  sz += getPageSize();
163  }
164 #ifdef _WIN32
165  if (_mapFile != INVALID_HANDLE_VALUE && _mapFile != NULL)
166  {
167  FlushFileBuffers(_file);
168  UnmapViewOfFile(_buffer);
169  CloseHandle(_mapFile);
170  }
171 #ifdef _WIN64
172  _mapFile = CreateFileMapping( _file, NULL, PAGE_READWRITE, (DWORD)((sz >> 32) & 0xffffffff), (DWORD)sz, NULL);
173 #else
174  _mapFile = CreateFileMapping( _file, NULL, PAGE_READWRITE, 0, (DWORD)sz, NULL);
175 #endif
176  if (_mapFile == INVALID_HANDLE_VALUE || _mapFile == NULL)
177  {
178  _buffer = 0;
179  _bufferLen = 0;
180  error("Failed to create map of log file");
181  }
182  else
183  {
184  _buffer = (char*)MapViewOfFile(_mapFile, FILE_MAP_ALL_ACCESS, 0, 0, sz);
185  if (_buffer == NULL)
186  {
187  std::ostringstream os;
188  os << "Failed to map log file to memory; buffer: " << (size_t)_buffer << " length: " << sz << " previous size: " << _bufferLen;
189  _buffer = 0;
190  _bufferLen = 0;
191  error(os.str());
192  }
193  }
194 #else
195  // If not at current size, extend the underlying file
196  if (sz > _bufferLen)
197  {
198  if (lseek(_fd, (off_t)sz - 1, SEEK_SET) == -1)
199  {
200  std::ostringstream os;
201  os << "Seek failed for buffer extension; buffer: " << (size_t)_buffer
202  << " length: " << _bufferLen << " pos: " << _bufferPos
203  << " requested new size: " << newSize_;
204  error(os.str());
205  }
206  if (!recovery_)
207  {
208  if (::write(_fd, "", 1) == -1)
209  {
210  std::ostringstream os;
211  os << "Failed to grow buffer; buffer: " << (size_t)_buffer << " length: "
212  << _bufferLen << " pos: " << _bufferPos << " requested new size: "
213  << newSize_;
214  error(os.str());
215  }
216  }
217  }
218 
219  void* result = NULL;
220  if (_buffer == NULL)
221  {
222  result = mmap(0, sz, PROT_WRITE | PROT_READ, MAP_SHARED, _fd, 0);
223  }
224  else if (_bufferLen < sz)
225  {
226 #if defined(linux)
227  result = mremap(_buffer, _bufferLen, sz, MREMAP_MAYMOVE);
228 #else
229  munmap(_buffer, _bufferLen);
230  result = mmap(0, sz, PROT_WRITE | PROT_READ, MAP_SHARED, _fd, 0);
231 #endif
232  }
233  if (result == MAP_FAILED || result == NULL)
234  {
235  std::ostringstream os;
236  os << "Failed to map log file to memory; buffer: "
237  << (size_t)_buffer << " length: " << sz
238  << " previous size: " << _bufferLen;
239  _buffer = 0;
240  _bufferLen = 0;
241  error(os.str());
242  }
243  else
244  {
245  _buffer = (char*)result;
246  }
247 #endif
248  if (_buffer)
249  {
250  _bufferLen = sz;
251  }
252  }
253 
254  private:
255  void error(const std::string & message)
256  {
257  std::ostringstream os;
258 #ifdef _WIN32
259  const size_t errorBufferSize = 1024;
260  char errorBuffer[errorBufferSize];
261  memset(errorBuffer, 0, errorBufferSize);
262  strerror_s(errorBuffer, errorBufferSize, errno);
263  os << message << ". Error is " << errorBuffer;
264 #else
265  os << message << ". Error is " << strerror(errno);
266 #endif
267  throw StoreException(os.str());
268  }
269 
270 #ifdef _WIN32
271  HANDLE _mapFile;
272  HANDLE _file;
273 #else
274  int _fd;
275 #endif
276  static size_t getPageSize()
277  {
278  static size_t pageSize;
279  if (pageSize == 0)
280  {
281 #ifdef _WIN32
282  SYSTEM_INFO SYS_INFO;
283  GetSystemInfo(&SYS_INFO);
284  pageSize = SYS_INFO.dwPageSize;
285 #else
286  pageSize = (size_t)sysconf(_SC_PAGESIZE);
287 #endif
288  }
289  return pageSize;
290  }
291 
292  };
293 
294 } // end namespace AMPS
295 
296 #endif //_MMAPSTOREBUFFER_H_
297 
virtual void setSize(size_t newSize_)
Set the size for the buffer.
Definition: MMapStoreBuffer.hpp:147
A Buffer implementation that uses memory for storage.
Definition: MemoryStoreBuffer.hpp:50
Core type, function, and class declarations for the AMPS C++ client.
A Buffer implementation that uses a memory mapped file as its storage.
Definition: MMapStoreBuffer.hpp:49
MMapStoreBuffer(const std::string &fileName_)
Create an MMapStoreBuffer using fileName_ as the name of the memory mapped file used for storage...
Definition: MMapStoreBuffer.hpp:57
Provides AMPS::MemoryStoreBuffer, used by an AMPS::HAClient to store messages in memory.
Definition: ampsplusplus.hpp:102