MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Win32AsyncFile.cpp
1 /*
2  Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 #include <ndb_global.h>
19 
20 #include "Win32AsyncFile.hpp"
21 
22 #include <signaldata/FsRef.hpp>
23 #include <signaldata/FsOpenReq.hpp>
24 #include <signaldata/FsReadWriteReq.hpp>
25 
26 Win32AsyncFile::Win32AsyncFile(SimulatedBlock& fs) :
27  AsyncFile(fs),hFile(INVALID_HANDLE_VALUE)
28 {
29 }
30 
31 Win32AsyncFile::~Win32AsyncFile()
32 {
33 
34 }
35 
36 int
37 Win32AsyncFile::init()
38 {
39  return 0;
40 }
41 
43 {
44  m_auto_sync_freq = 0;
45  m_write_wo_sync = 0;
46  m_open_flags = request->par.open.flags;
47 
48  // for open.flags, see signal FSOPENREQ
49  DWORD dwCreationDisposition;
50  DWORD dwDesiredAccess = 0;
51  DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
60  DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
61  Uint32 flags = request->par.open.flags;
62 
63  // Convert file open flags from Solaris to Windows
64  if ((flags & FsOpenReq::OM_CREATE) && (flags & FsOpenReq::OM_TRUNCATE)){
65  dwCreationDisposition = CREATE_ALWAYS;
66  } else if (flags & FsOpenReq::OM_TRUNCATE){
67  dwCreationDisposition = TRUNCATE_EXISTING;
68  } else if (flags & (FsOpenReq::OM_CREATE|FsOpenReq::OM_CREATE_IF_NONE)){
69  dwCreationDisposition = CREATE_NEW;
70  } else {
71  dwCreationDisposition = OPEN_EXISTING;
72  }
73 
74  switch(flags & 3){
75  case FsOpenReq::OM_READONLY:
76  dwDesiredAccess = GENERIC_READ;
77  break;
78  case FsOpenReq::OM_WRITEONLY:
79  dwDesiredAccess = GENERIC_WRITE;
80  break;
81  case FsOpenReq::OM_READWRITE:
82  dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
83  break;
84  default:
85  request->error = 1000;
86  break;
87  return;
88  }
89 
90  hFile = CreateFile(theFileName.c_str(), dwDesiredAccess, dwShareMode,
91  0, dwCreationDisposition, dwFlagsAndAttributes, 0);
92 
93  if(INVALID_HANDLE_VALUE == hFile) {
94  request->error = GetLastError();
95  if(((ERROR_PATH_NOT_FOUND == request->error) || (ERROR_INVALID_NAME == request->error))
96  && (flags & (FsOpenReq::OM_CREATE|FsOpenReq::OM_CREATE_IF_NONE))) {
97  createDirectories();
98  hFile = CreateFile(theFileName.c_str(), dwDesiredAccess, dwShareMode,
99  0, dwCreationDisposition, dwFlagsAndAttributes, 0);
100 
101  if(INVALID_HANDLE_VALUE == hFile)
102  request->error = GetLastError();
103  else
104  request->error = 0;
105  }
106  }
107  else {
108  request->error = 0;
109  }
110 
111  if (flags & FsOpenReq::OM_INIT)
112  {
113  LARGE_INTEGER off;
114  off.QuadPart= 0;
115  LARGE_INTEGER sz;
116  sz.QuadPart= request->par.open.file_size;
117  char buf[4096];
118  bzero(buf,sizeof(buf));
119  while(off.QuadPart < sz.QuadPart)
120  {
121  BOOL r= SetFilePointerEx(hFile, off, NULL, FILE_BEGIN);
122  if(r==0)
123  {
124  request->error= GetLastError();
125  return;
126  }
127  DWORD dwWritten;
128  BOOL bWrite= WriteFile(hFile, buf, sizeof(buf), &dwWritten, 0);
129  if(!bWrite || dwWritten!=sizeof(buf))
130  {
131  request->error= GetLastError();
132  }
133  off.QuadPart+=sizeof(buf);
134  }
135  off.QuadPart= 0;
136  BOOL r= SetFilePointerEx(hFile, off, NULL, FILE_BEGIN);
137  if(r==0)
138  {
139  request->error= GetLastError();
140  return;
141  }
142 
143  /* Write initial data */
144  SignalT<25> tmp;
145  Signal * signal = (Signal*)(&tmp);
146  bzero(signal, sizeof(tmp));
147  FsReadWriteReq* req = (FsReadWriteReq*)signal->getDataPtrSend();
148  Uint32 index = 0;
149  Uint32 block = refToMain(request->theUserReference);
150  Uint32 instance = refToInstance(request->theUserReference);
151 
152  off.QuadPart= 0;
153  sz.QuadPart= request->par.open.file_size;
154  while(off.QuadPart < sz.QuadPart)
155  {
156  req->filePointer = 0; // DATA 0
157  req->userPointer = request->theUserPointer; // DATA 2
158  req->numberOfPages = 1; // DATA 5
159  req->varIndex = index++;
160  req->data.pageData[0] = m_page_ptr.i;
161 
162  m_fs.EXECUTE_DIRECT(block, GSN_FSWRITEREQ, signal,
163  FsReadWriteReq::FixedLength + 1,
164  instance // wl4391_todo This EXECUTE_DIRECT is thread safe
165  );
166  Uint32 size = request->par.open.page_size;
167  char* buf = (char*)m_page_ptr.p;
168  DWORD dwWritten;
169  while(size > 0){
170  BOOL bWrite= WriteFile(hFile, buf, size, &dwWritten, 0);
171  if(!bWrite || dwWritten!=size)
172  {
173  request->error= GetLastError();
174  }
175  size -= dwWritten;
176  buf += dwWritten;
177  }
178  if(size != 0)
179  {
180  int err = errno;
181  /* close(theFd);
182  unlink(theFileName.c_str());*/
183  request->error = err;
184  return;
185  }
186  off.QuadPart += request->par.open.page_size;
187  }
188 
189  off.QuadPart= 0;
190  r= SetFilePointerEx(hFile, off, NULL, FILE_BEGIN);
191  if(r==0)
192  {
193  request->error= GetLastError();
194  return;
195  }
196  }
197 
198  return;
199 }
200 
201 int
202 Win32AsyncFile::readBuffer(Request* req, char * buf, size_t size, off_t offset)
203 {
204  req->par.readWrite.pages[0].size = 0;
205 
206  while (size > 0) {
207  size_t bytes_read = 0;
208 
209  OVERLAPPED ov;
210  bzero(&ov, sizeof(ov));
211 
212  LARGE_INTEGER li;
213  li.QuadPart = offset;
214  ov.Offset = li.LowPart;
215  ov.OffsetHigh = li.HighPart;
216 
217  DWORD dwBytesRead;
218  BOOL bRead = ReadFile(hFile,
219  buf,
220  size,
221  &dwBytesRead,
222  &ov);
223  if(!bRead){
224  int err = GetLastError();
225  if (err == ERROR_HANDLE_EOF && req->action == Request::readPartial)
226  {
227  return 0;
228  }
229  return err;
230  }
231  bytes_read = dwBytesRead;
232 
233  req->par.readWrite.pages[0].size += bytes_read;
234  if(bytes_read == 0){
235  if(req->action == Request::readPartial)
236  {
237  return 0;
238  }
239  DEBUG(ndbout_c("Read underflow %d %d\n %x\n%d %d",
240  size, offset, buf, bytes_read, return_value));
241  return ERR_ReadUnderflow;
242  }
243 
244  if(bytes_read != size){
245  DEBUG(ndbout_c("Warning partial read %d != %d",
246  bytes_read, size));
247  }
248 
249  buf += bytes_read;
250  size -= bytes_read;
251  offset += bytes_read;
252  }
253  return 0;
254 }
255 
256 int
257 Win32AsyncFile::writeBuffer(const char * buf, size_t size, off_t offset)
258 {
259  size_t chunk_size = 256 * 1024;
260  size_t bytes_to_write = chunk_size;
261 
262  m_write_wo_sync += size;
263 
264  while (size > 0) {
265  OVERLAPPED ov;
266  bzero(&ov, sizeof(ov));
267 
268  LARGE_INTEGER li;
269  li.QuadPart = offset;
270  ov.Offset = li.LowPart;
271  ov.OffsetHigh = li.HighPart;
272 
273  if (size < bytes_to_write){
274  // We are at the last chunk
275  bytes_to_write = size;
276  }
277  size_t bytes_written = 0;
278 
279  DWORD dwWritten;
280  BOOL bWrite = WriteFile(hFile, buf, bytes_to_write, &dwWritten, &ov);
281  if(!bWrite) {
282  return GetLastError();
283  }
284  bytes_written = dwWritten;
285  if (bytes_written != bytes_to_write) {
286  DEBUG(ndbout_c("Warning partial write %d != %d", bytes_written, bytes_to_write));
287  }
288 
289  buf += bytes_written;
290  size -= bytes_written;
291  offset += bytes_written;
292  }
293  return 0;
294 }
295 
296 void
297 Win32AsyncFile::closeReq(Request * request)
298 {
299  if (m_open_flags & (
300  FsOpenReq::OM_WRITEONLY |
301  FsOpenReq::OM_READWRITE |
302  FsOpenReq::OM_APPEND )) {
303  syncReq(request);
304  }
305 
306  if(!CloseHandle(hFile)) {
307  request->error = GetLastError();
308  }
309  hFile = INVALID_HANDLE_VALUE;
310 }
311 
312 bool Win32AsyncFile::isOpen(){
313  return (hFile != INVALID_HANDLE_VALUE);
314 }
315 
316 
317 void
318 Win32AsyncFile::syncReq(Request * request)
319 {
320  if(m_auto_sync_freq && m_write_wo_sync == 0){
321  return;
322  }
323  if(!FlushFileBuffers(hFile)) {
324  request->error = GetLastError();
325  return;
326  }
327  m_write_wo_sync = 0;
328 }
329 
330 void
331 Win32AsyncFile::appendReq(Request * request){
332 
333  const char * buf = request->par.append.buf;
334  Uint32 size = Uint32(request->par.append.size);
335 
336  m_write_wo_sync += size;
337 
338  DWORD dwWritten = 0;
339  while(size > 0){
340  if(!WriteFile(hFile, buf, size, &dwWritten, 0)){
341  request->error = GetLastError();
342  return ;
343  }
344 
345  buf += dwWritten;
346  size -= dwWritten;
347  }
348 
349  if(m_auto_sync_freq && m_write_wo_sync > m_auto_sync_freq){
350  syncReq(request);
351  }
352 }
353 
354 void
355 Win32AsyncFile::removeReq(Request * request)
356 {
357  if(!DeleteFile(theFileName.c_str())) {
358  request->error = GetLastError();
359  }
360 }
361 
362 void
363 Win32AsyncFile::rmrfReq(Request * request, const char * src, bool removePath){
364  if (!request->par.rmrf.directory)
365  {
366  // Remove file
367  if (!DeleteFile(src))
368  {
369  DWORD dwError = GetLastError();
370  if (dwError != ERROR_FILE_NOT_FOUND)
371  request->error = dwError;
372  }
373  return;
374  }
375 
376  char path[PATH_MAX];
377  strcpy(path, src);
378  strcat(path, "\\*");
379 
380  WIN32_FIND_DATA ffd;
381  HANDLE hFindFile;
382 loop:
383  hFindFile = FindFirstFile(path, &ffd);
384  if (INVALID_HANDLE_VALUE == hFindFile)
385  {
386  DWORD dwError = GetLastError();
387  if (dwError != ERROR_PATH_NOT_FOUND)
388  request->error = dwError;
389  return;
390  }
391  path[strlen(path) - 1] = 0; // remove '*'
392 
393  do {
394  if (0 != strcmp(".", ffd.cFileName) && 0 != strcmp("..", ffd.cFileName))
395  {
396  int len = strlen(path);
397  strcat(path, ffd.cFileName);
398  if(DeleteFile(path) || RemoveDirectory(path))
399  {
400  path[len] = 0;
401  continue;
402  }//if
403 
404  FindClose(hFindFile);
405  strcat(path, "\\*");
406  goto loop;
407  }
408  } while(FindNextFile(hFindFile, &ffd));
409 
410  FindClose(hFindFile);
411  path[strlen(path)-1] = 0; // remove '\'
412  if (strcmp(src, path) != 0)
413  {
414  char * t = strrchr(path, '\\');
415  t[1] = '*';
416  t[2] = 0;
417  goto loop;
418  }
419 
420  if(removePath && !RemoveDirectory(src))
421  request->error = GetLastError();
422 }
423 
424 void Win32AsyncFile::createDirectories()
425 {
426  char* tmp;
427  const char * name = theFileName.c_str();
428  const char * base = theFileName.get_base_name();
429  while((tmp = (char *)strstr(base, DIR_SEPARATOR)))
430  {
431  char t = tmp[0];
432  tmp[0] = 0;
433  CreateDirectory(name, 0);
434  tmp[0] = t;
435  base = tmp + sizeof(DIR_SEPARATOR);
436  }
437 }