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