AMPS C/C++ Client Class Reference
AMPS C/C++ Client Version 5.3.4.4
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 #ifdef _WIN32
58  MMapStoreBuffer(const std::string& fileName_)
59  : MemoryStoreBuffer(MemoryStoreBuffer::EMPTY)
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  }
85 #else
86  MMapStoreBuffer(const std::string& fileName_)
88  {
89  _fd = ::open(fileName_.c_str(), O_CREAT | O_RDWR, (mode_t)0644);
90  struct stat statBuf;
91  memset(&statBuf, 0, sizeof(statBuf));
92  if (fstat(_fd, &statBuf) == -1)
93  {
94  std::ostringstream os;
95  os << "Failed to stat file " << fileName_ << " for MMapStoreBuffer";
96  error(os.str());
97  }
98  bool recovery = statBuf.st_size >= (ssize_t)AMPS_MEMORYBUFFER_DEFAULT_LENGTH;
99  _setSize(recovery ? (size_t)statBuf.st_size
100  : AMPS_MEMORYBUFFER_DEFAULT_LENGTH,
101  recovery);
102  }
103 #endif
104 
105  ~MMapStoreBuffer()
106  {
107  if (_buffer)
108  {
109  close();
110  }
111  }
112 
113  void close()
114  {
115  sync();
116 #ifdef _WIN32
117  FlushFileBuffers(_file);
118  UnmapViewOfFile(_buffer);
119  CloseHandle(_mapFile);
120  CloseHandle(_file);
121  _mapFile = INVALID_HANDLE_VALUE;
122  _file = INVALID_HANDLE_VALUE;
123 #else
124  munmap(_buffer, _bufferLen);
125  ::close(_fd);
126  _fd = 0;
127 #endif
128  _buffer = NULL;
129  _bufferLen = 0;
130  }
131 
132  void sync()
133  {
134  if (_buffer != NULL && _bufferLen)
135  {
136 #ifdef _WIN32
137  if (!FlushViewOfFile(_buffer, _bufferPos))
138 #else
139  if (msync(_buffer, _bufferPos, MS_ASYNC) != 0)
140 #endif
141  {
142  std::ostringstream os;
143  os << "Failed to sync mapped memory; buffer: " << (size_t)_buffer
144  << " pos: " << _bufferPos;
145  error(os.str());
146  }
147  }
148  }
149 
150  virtual void setSize(size_t newSize_)
151  {
152  _setSize(newSize_);
153  }
154 
155  void _setSize(size_t newSize_, bool recovery_ = false)
156  {
157  if (_bufferLen > 0)
158  {
159  sync();
160  }
161  // Make sure we're using a multiple of page size
162  size_t sz = newSize_ & (size_t)(~(getPageSize() - 1));
163  if (sz < newSize_)
164  {
165  sz += getPageSize();
166  }
167 #ifdef _WIN32
168  if (_mapFile != INVALID_HANDLE_VALUE && _mapFile != NULL)
169  {
170  FlushFileBuffers(_file);
171  UnmapViewOfFile(_buffer);
172  CloseHandle(_mapFile);
173  }
174 #ifdef _WIN64
175  _mapFile = CreateFileMapping( _file, NULL, PAGE_READWRITE, (DWORD)((sz >> 32) & 0xffffffff), (DWORD)sz, NULL);
176 #else
177  _mapFile = CreateFileMapping( _file, NULL, PAGE_READWRITE, 0, (DWORD)sz, NULL);
178 #endif
179  if (_mapFile == INVALID_HANDLE_VALUE || _mapFile == NULL)
180  {
181  _buffer = 0;
182  _bufferLen = 0;
183  error("Failed to create map of log file");
184  }
185  else
186  {
187  _buffer = (char*)MapViewOfFile(_mapFile, FILE_MAP_ALL_ACCESS, 0, 0, sz);
188  if (_buffer == NULL)
189  {
190  std::ostringstream os;
191  os << "Failed to map log file to memory; buffer: " << (size_t)_buffer << " length: " << sz << " previous size: " << _bufferLen;
192  _buffer = 0;
193  _bufferLen = 0;
194  error(os.str());
195  }
196  }
197 #else
198  // If not at current size, extend the underlying file
199  if (sz > _bufferLen)
200  {
201  if (lseek(_fd, (off_t)sz - 1, SEEK_SET) == -1)
202  {
203  std::ostringstream os;
204  os << "Seek failed for buffer extension; buffer: " << (size_t)_buffer
205  << " length: " << _bufferLen << " pos: " << _bufferPos
206  << " requested new size: " << newSize_;
207  error(os.str());
208  }
209  if (!recovery_)
210  {
211  if (::write(_fd, "", 1) == -1)
212  {
213  std::ostringstream os;
214  os << "Failed to grow buffer; buffer: " << (size_t)_buffer << " length: "
215  << _bufferLen << " pos: " << _bufferPos << " requested new size: "
216  << newSize_;
217  error(os.str());
218  }
219  }
220  }
221 
222  void* result = NULL;
223  if (_buffer == NULL)
224  {
225  result = mmap(0, sz, PROT_WRITE | PROT_READ, MAP_SHARED, _fd, 0);
226  }
227  else if (_bufferLen < sz)
228  {
229 #if defined(linux)
230  result = mremap(_buffer, _bufferLen, sz, MREMAP_MAYMOVE);
231 #else
232  munmap(_buffer, _bufferLen);
233  result = mmap(0, sz, PROT_WRITE | PROT_READ, MAP_SHARED, _fd, 0);
234 #endif
235  }
236  if (result == MAP_FAILED || result == NULL)
237  {
238  std::ostringstream os;
239  os << "Failed to map log file to memory; buffer: "
240  << (size_t)_buffer << " length: " << sz
241  << " previous size: " << _bufferLen;
242  _buffer = 0;
243  _bufferLen = 0;
244  error(os.str());
245  }
246  else
247  {
248  _buffer = (char*)result;
249  }
250 #endif
251  if (_buffer)
252  {
253  _bufferLen = sz;
254  }
255  }
256 
257  private:
258  void error(const std::string & message)
259  {
260  std::ostringstream os;
261 #ifdef _WIN32
262  const size_t errorBufferSize = 1024;
263  char errorBuffer[errorBufferSize];
264  memset(errorBuffer, 0, errorBufferSize);
265  strerror_s(errorBuffer, errorBufferSize, errno);
266  os << message << ". Error is " << errorBuffer;
267 #else
268  os << message << ". Error is " << strerror(errno);
269 #endif
270  throw StoreException(os.str());
271  }
272 
273 #ifdef _WIN32
274  HANDLE _mapFile;
275  HANDLE _file;
276 #else
277  int _fd;
278 #endif
279  static size_t getPageSize()
280  {
281  static size_t pageSize;
282  if (pageSize == 0)
283  {
284 #ifdef _WIN32
285  SYSTEM_INFO SYS_INFO;
286  GetSystemInfo(&SYS_INFO);
287  pageSize = SYS_INFO.dwPageSize;
288 #else
289  pageSize = (size_t)sysconf(_SC_PAGESIZE);
290 #endif
291  }
292  return pageSize;
293  }
294 
295  };
296 
297 } // end namespace AMPS
298 
299 #endif //_MMAPSTOREBUFFER_H_
300 
virtual void setSize(size_t newSize_)
Set the size for the buffer.
Definition: MMapStoreBuffer.hpp:150
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:86
Provides AMPS::MemoryStoreBuffer, used by an AMPS::HAClient to store messages in memory.
Definition: ampsplusplus.hpp:102