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