passenger 5.0.8 → 5.0.9
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of passenger might be problematic. Click here for more details.
- checksums.yaml +8 -8
- checksums.yaml.gz.asc +7 -7
- data.tar.gz.asc +7 -7
- data/.editorconfig +20 -0
- data/CHANGELOG +21 -0
- data/bin/passenger-install-apache2-module +3 -1
- data/build/agents.rb +7 -5
- data/build/basics.rb +3 -3
- data/build/common_library.rb +52 -30
- data/build/cxx_tests.rb +20 -13
- data/build/misc.rb +5 -5
- data/doc/Design and Architecture.html +1 -1
- data/doc/Design and Architecture.txt +1 -1
- data/doc/Packaging.html +4 -4
- data/doc/Packaging.txt.md +4 -4
- data/doc/Users guide Apache.html +22 -9
- data/doc/Users guide Apache.idmap.txt +4 -2
- data/doc/Users guide Apache.txt +2 -0
- data/doc/Users guide Nginx.html +22 -9
- data/doc/Users guide Nginx.idmap.txt +4 -2
- data/doc/Users guide Nginx.txt +2 -0
- data/doc/Users guide Standalone.html +14 -9
- data/doc/Users guide Standalone.idmap.txt +4 -2
- data/doc/users_guide_snippets/installation.txt +10 -6
- data/ext/apache2/Hooks.cpp +13 -2
- data/ext/common/ApplicationPool2/Pool/Inspection.h +8 -3
- data/ext/common/BackgroundEventLoop.cpp +249 -67
- data/ext/common/BackgroundEventLoop.h +5 -5
- data/ext/common/Constants.h +1 -1
- data/ext/common/InstanceDirectory.h +8 -6
- data/ext/common/ServerKit/Context.h +8 -2
- data/ext/common/ServerKit/FileBufferedChannel.h +262 -226
- data/ext/common/ServerKit/HeaderTable.h +28 -3
- data/ext/common/ServerKit/HttpHeaderParser.h +37 -13
- data/ext/common/ServerKit/HttpServer.h +17 -1
- data/ext/common/ServerKit/Implementation.cpp +2 -0
- data/ext/common/ServerKit/Server.h +25 -28
- data/ext/common/Utils/IOUtils.cpp +11 -0
- data/ext/common/Utils/ProcessMetricsCollector.h +4 -0
- data/ext/common/Utils/StrIntUtils.cpp +11 -7
- data/ext/common/Utils/StrIntUtils.h +1 -1
- data/ext/common/Utils/StrIntUtilsNoStrictAliasing.cpp +21 -16
- data/ext/common/agents/Base.cpp +6 -0
- data/ext/common/agents/Base.h +2 -0
- data/ext/common/agents/HelperAgent/AdminServer.h +25 -25
- data/ext/common/agents/HelperAgent/Main.cpp +37 -12
- data/ext/common/agents/HelperAgent/RequestHandler.h +18 -20
- data/ext/common/agents/HelperAgent/RequestHandler/AppResponse.h +4 -0
- data/ext/common/agents/HelperAgent/RequestHandler/ForwardResponse.cpp +10 -6
- data/ext/common/agents/HelperAgent/RequestHandler/Hooks.cpp +2 -0
- data/ext/common/agents/HelperAgent/RequestHandler/InitRequest.cpp +1 -1
- data/ext/common/agents/HelperAgent/RequestHandler/SendRequest.cpp +1 -1
- data/ext/common/agents/HelperAgent/RequestHandler/Utils.cpp +9 -2
- data/ext/common/agents/HelperAgent/ResponseCache.h +11 -11
- data/ext/common/agents/LoggingAgent/AdminServer.h +8 -8
- data/ext/common/agents/LoggingAgent/Main.cpp +6 -5
- data/ext/common/agents/Watchdog/AdminServer.h +13 -13
- data/ext/common/agents/Watchdog/Main.cpp +8 -3
- data/ext/libuv/.gitignore +72 -0
- data/ext/libuv/AUTHORS +199 -0
- data/ext/libuv/ChangeLog +2023 -0
- data/ext/libuv/LICENSE +46 -0
- data/ext/libuv/Makefile.am +336 -0
- data/ext/libuv/README.md +197 -0
- data/ext/libuv/checksparse.sh +233 -0
- data/ext/libuv/common.gypi +210 -0
- data/ext/libuv/configure.ac +67 -0
- data/ext/libuv/gyp_uv.py +96 -0
- data/ext/libuv/include/android-ifaddrs.h +54 -0
- data/ext/libuv/include/pthread-fixes.h +72 -0
- data/ext/libuv/include/tree.h +768 -0
- data/ext/libuv/include/uv-aix.h +32 -0
- data/ext/libuv/include/uv-bsd.h +34 -0
- data/ext/libuv/include/uv-darwin.h +61 -0
- data/ext/libuv/include/uv-errno.h +418 -0
- data/ext/libuv/include/uv-linux.h +34 -0
- data/ext/libuv/include/uv-sunos.h +44 -0
- data/ext/libuv/include/uv-threadpool.h +37 -0
- data/ext/libuv/include/uv-unix.h +383 -0
- data/ext/libuv/include/uv-version.h +39 -0
- data/ext/libuv/include/uv.h +1455 -0
- data/ext/libuv/libuv.pc.in +11 -0
- data/ext/libuv/m4/.gitignore +4 -0
- data/ext/libuv/m4/as_case.m4 +21 -0
- data/ext/libuv/m4/libuv-check-flags.m4 +319 -0
- data/ext/libuv/src/fs-poll.c +255 -0
- data/ext/libuv/src/heap-inl.h +245 -0
- data/ext/libuv/src/inet.c +313 -0
- data/ext/libuv/src/queue.h +92 -0
- data/ext/libuv/src/threadpool.c +303 -0
- data/ext/libuv/src/unix/aix.c +1240 -0
- data/ext/libuv/src/unix/android-ifaddrs.c +703 -0
- data/ext/libuv/src/unix/async.c +284 -0
- data/ext/libuv/src/unix/atomic-ops.h +60 -0
- data/ext/libuv/src/unix/core.c +985 -0
- data/ext/libuv/src/unix/darwin-proctitle.c +206 -0
- data/ext/libuv/src/unix/darwin.c +331 -0
- data/ext/libuv/src/unix/dl.c +83 -0
- data/ext/libuv/src/unix/freebsd.c +435 -0
- data/ext/libuv/src/unix/fs.c +1189 -0
- data/ext/libuv/src/unix/fsevents.c +899 -0
- data/ext/libuv/src/unix/getaddrinfo.c +202 -0
- data/ext/libuv/src/unix/getnameinfo.c +120 -0
- data/ext/libuv/src/unix/internal.h +314 -0
- data/ext/libuv/src/unix/kqueue.c +418 -0
- data/ext/libuv/src/unix/linux-core.c +876 -0
- data/ext/libuv/src/unix/linux-inotify.c +257 -0
- data/ext/libuv/src/unix/linux-syscalls.c +471 -0
- data/ext/libuv/src/unix/linux-syscalls.h +158 -0
- data/ext/libuv/src/unix/loop-watcher.c +63 -0
- data/ext/libuv/src/unix/loop.c +135 -0
- data/ext/libuv/src/unix/netbsd.c +368 -0
- data/ext/libuv/src/unix/openbsd.c +384 -0
- data/ext/libuv/src/unix/pipe.c +288 -0
- data/ext/libuv/src/unix/poll.c +113 -0
- data/ext/libuv/src/unix/process.c +551 -0
- data/ext/libuv/src/unix/proctitle.c +102 -0
- data/ext/libuv/src/unix/pthread-fixes.c +103 -0
- data/ext/libuv/src/unix/signal.c +465 -0
- data/ext/libuv/src/unix/spinlock.h +53 -0
- data/ext/libuv/src/unix/stream.c +1598 -0
- data/ext/libuv/src/unix/sunos.c +763 -0
- data/ext/libuv/src/unix/tcp.c +327 -0
- data/ext/libuv/src/unix/thread.c +519 -0
- data/ext/libuv/src/unix/timer.c +172 -0
- data/ext/libuv/src/unix/tty.c +265 -0
- data/ext/libuv/src/unix/udp.c +833 -0
- data/ext/libuv/src/uv-common.c +544 -0
- data/ext/libuv/src/uv-common.h +214 -0
- data/ext/libuv/src/version.c +49 -0
- data/ext/libuv/uv.gyp +487 -0
- data/ext/nginx/ContentHandler.c +21 -10
- data/ext/nginx/ngx_http_passenger_module.c +7 -0
- data/ext/oxt/implementation.cpp +9 -2
- data/ext/oxt/initialize.hpp +5 -1
- data/lib/phusion_passenger.rb +3 -3
- data/lib/phusion_passenger/admin_tools/instance.rb +10 -6
- data/lib/phusion_passenger/admin_tools/instance_registry.rb +6 -2
- data/lib/phusion_passenger/packaging.rb +3 -4
- data/lib/phusion_passenger/platform_info.rb +13 -1
- data/lib/phusion_passenger/platform_info/apache.rb +15 -4
- data/lib/phusion_passenger/platform_info/apache_detector.rb +5 -1
- data/lib/phusion_passenger/rack/thread_handler_extension.rb +184 -99
- data/lib/phusion_passenger/request_handler/thread_handler.rb +13 -6
- data/lib/phusion_passenger/standalone/start_command.rb +2 -2
- data/resources/templates/apache2/apache_install_broken.txt.erb +2 -1
- metadata +99 -22
- metadata.gz.asc +7 -7
- data/ext/libeio/Changes +0 -76
- data/ext/libeio/LICENSE +0 -36
- data/ext/libeio/Makefile.am +0 -15
- data/ext/libeio/Makefile.in +0 -694
- data/ext/libeio/aclocal.m4 +0 -9418
- data/ext/libeio/autogen.sh +0 -3
- data/ext/libeio/config.guess +0 -1540
- data/ext/libeio/config.h.in +0 -136
- data/ext/libeio/config.sub +0 -1779
- data/ext/libeio/configure +0 -14822
- data/ext/libeio/configure.ac +0 -22
- data/ext/libeio/demo.c +0 -194
- data/ext/libeio/ecb.h +0 -714
- data/ext/libeio/eio.c +0 -2818
- data/ext/libeio/eio.h +0 -414
- data/ext/libeio/install-sh +0 -520
- data/ext/libeio/libeio.m4 +0 -195
- data/ext/libeio/ltmain.sh +0 -9636
- data/ext/libeio/missing +0 -376
- data/ext/libeio/xthread.h +0 -166
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
-
* Copyright (c) 2011
|
3
|
+
* Copyright (c) 2011-2015 Phusion
|
4
4
|
*
|
5
5
|
* "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
|
6
6
|
*
|
@@ -31,7 +31,7 @@
|
|
31
31
|
|
32
32
|
extern "C" {
|
33
33
|
struct ev_loop;
|
34
|
-
struct
|
34
|
+
struct uv_loop_s;
|
35
35
|
}
|
36
36
|
|
37
37
|
namespace Passenger {
|
@@ -45,12 +45,12 @@ namespace Passenger {
|
|
45
45
|
* Implements a libev event loop that runs in a background thread.
|
46
46
|
*/
|
47
47
|
struct BackgroundEventLoop {
|
48
|
-
struct ev_loop *
|
49
|
-
|
48
|
+
struct ev_loop *libev_loop;
|
49
|
+
struct uv_loop_s *libuv_loop;
|
50
50
|
boost::shared_ptr<SafeLibev> safe;
|
51
51
|
BackgroundEventLoopPrivate *priv;
|
52
52
|
|
53
|
-
BackgroundEventLoop(bool scalable = false, bool
|
53
|
+
BackgroundEventLoop(bool scalable = false, bool usesLibuv = true);
|
54
54
|
~BackgroundEventLoop();
|
55
55
|
|
56
56
|
void start(const string &threadName = "", unsigned int stackSize = 1024 * 1024);
|
data/ext/common/Constants.h
CHANGED
@@ -49,6 +49,7 @@ class InstanceDirectory {
|
|
49
49
|
public:
|
50
50
|
struct CreationOptions {
|
51
51
|
string prefix;
|
52
|
+
uid_t originalUid;
|
52
53
|
bool userSwitching;
|
53
54
|
uid_t defaultUid;
|
54
55
|
gid_t defaultGid;
|
@@ -56,6 +57,7 @@ public:
|
|
56
57
|
|
57
58
|
CreationOptions()
|
58
59
|
: prefix("passenger"),
|
60
|
+
originalUid(geteuid()),
|
59
61
|
userSwitching(true),
|
60
62
|
defaultUid(USER_NOT_GIVEN),
|
61
63
|
defaultGid(GROUP_NOT_GIVEN)
|
@@ -108,17 +110,17 @@ private:
|
|
108
110
|
|
109
111
|
void initializeInstanceDirectory(const CreationOptions &options) {
|
110
112
|
createPropertyFile(options);
|
111
|
-
createAgentSocketsSubdir();
|
113
|
+
createAgentSocketsSubdir(options);
|
112
114
|
createAppSocketsSubdir(options);
|
113
115
|
createLockFile();
|
114
116
|
}
|
115
117
|
|
116
|
-
bool runningAsRoot() const {
|
117
|
-
return
|
118
|
+
bool runningAsRoot(const CreationOptions &options) const {
|
119
|
+
return options.originalUid == 0;
|
118
120
|
}
|
119
121
|
|
120
|
-
void createAgentSocketsSubdir() {
|
121
|
-
if (runningAsRoot()) {
|
122
|
+
void createAgentSocketsSubdir(const CreationOptions &options) {
|
123
|
+
if (runningAsRoot(options)) {
|
122
124
|
/* The server socket must be accessible by the web server
|
123
125
|
* and by the apps, which may run as complete different users,
|
124
126
|
* so this subdirectory must be world-accessible.
|
@@ -130,7 +132,7 @@ private:
|
|
130
132
|
}
|
131
133
|
|
132
134
|
void createAppSocketsSubdir(const CreationOptions &options) {
|
133
|
-
if (runningAsRoot()) {
|
135
|
+
if (runningAsRoot(options)) {
|
134
136
|
if (options.userSwitching) {
|
135
137
|
/* Each app may be running as a different user,
|
136
138
|
* so the apps.s subdirectory must be world-writable.
|
@@ -35,6 +35,10 @@
|
|
35
35
|
#include <Utils/json.h>
|
36
36
|
#include <Utils/JsonUtils.h>
|
37
37
|
|
38
|
+
extern "C" {
|
39
|
+
struct uv_loop_s;
|
40
|
+
}
|
41
|
+
|
38
42
|
namespace Passenger {
|
39
43
|
namespace ServerKit {
|
40
44
|
|
@@ -66,12 +70,14 @@ private:
|
|
66
70
|
|
67
71
|
public:
|
68
72
|
SafeLibevPtr libev;
|
73
|
+
struct uv_loop_s *libuv;
|
69
74
|
struct MemoryKit::mbuf_pool mbuf_pool;
|
70
75
|
string secureModePassword;
|
71
76
|
FileBufferedChannelConfig defaultFileBufferedChannelConfig;
|
72
77
|
|
73
|
-
Context(const SafeLibevPtr &_libev)
|
74
|
-
: libev(_libev)
|
78
|
+
Context(const SafeLibevPtr &_libev, struct uv_loop_s *_libuv)
|
79
|
+
: libev(_libev),
|
80
|
+
libuv(_libuv)
|
75
81
|
{
|
76
82
|
initialize();
|
77
83
|
}
|
@@ -31,7 +31,7 @@
|
|
31
31
|
#include <boost/move/move.hpp>
|
32
32
|
#include <boost/atomic.hpp>
|
33
33
|
#include <sys/types.h>
|
34
|
-
#include <
|
34
|
+
#include <uv.h>
|
35
35
|
#include <cassert>
|
36
36
|
#include <cstddef>
|
37
37
|
#include <cstring>
|
@@ -58,6 +58,13 @@ using namespace std;
|
|
58
58
|
#define FBC_DEBUG_FROM_STATIC(expr) \
|
59
59
|
P_TRACE(3, "[FBC " << (void *) self << "] " << expr)
|
60
60
|
|
61
|
+
#define FBC_DEBUG_FROM_CALLBACK(context, expr) \
|
62
|
+
P_TRACE(3, "[FBC " << (void *) context->logbase << "] " << expr)
|
63
|
+
#define FBC_ERROR_FROM_CALLBACK(context, expr) \
|
64
|
+
P_ERROR("[FBC " << (void *) context->logbase << "] " << expr)
|
65
|
+
#define FBC_CRITICAL_FROM_CALLBACK(context, expr) \
|
66
|
+
P_CRITICAL("[FBC " << (void *) context->logbase << "] " << expr)
|
67
|
+
|
61
68
|
|
62
69
|
/**
|
63
70
|
* Adds "unlimited" buffering capability to a Channel. A Channel has a buffer size
|
@@ -196,51 +203,81 @@ public:
|
|
196
203
|
|
197
204
|
|
198
205
|
private:
|
199
|
-
|
206
|
+
/**
|
207
|
+
* A structure containing the details of a libuv asynchronous
|
208
|
+
* filesystem I/O request.
|
209
|
+
*
|
210
|
+
* The I/O callback is responsible for destroying its corresponding
|
211
|
+
* FileIOContext object.
|
212
|
+
*/
|
213
|
+
struct FileIOContext {
|
214
|
+
/**
|
215
|
+
* A back pointer to the FileBufferedChannel that created this
|
216
|
+
* IOContext.
|
217
|
+
*
|
218
|
+
* This pointer is set to NULL when this I/O operation is
|
219
|
+
* canceled (through the `cancel()` method). Cancelation
|
220
|
+
* occurs when the FileBufferedChannel is about to be deinitialized.
|
221
|
+
* So be sure to check for cancellation (using `isCanceled`)
|
222
|
+
* before using the backpointer.
|
223
|
+
*/
|
200
224
|
FileBufferedChannel *self;
|
201
|
-
SafeLibevPtr libev;
|
202
|
-
eio_req *req;
|
203
|
-
boost::atomic<bool> canceled;
|
204
225
|
/**
|
205
|
-
*
|
206
|
-
*
|
207
|
-
*
|
208
|
-
*
|
226
|
+
* Pointers to the libev and libuv loops that this FileBufferedChannel
|
227
|
+
* used. We keep the pointers here so that callbacks can perform
|
228
|
+
* asynchronous I/O operations as part of their cleanup, even in the
|
229
|
+
* event the original I/O operation is canceled.
|
230
|
+
*
|
231
|
+
* I/O callbacks do not have to worry about whether these pointers are
|
232
|
+
* stale, because callbacks are run inside the event loop, and we stop the
|
233
|
+
* event loop before destryoing it.
|
209
234
|
*/
|
210
|
-
|
235
|
+
SafeLibevPtr libev;
|
236
|
+
uv_loop_t *libuv;
|
237
|
+
/* req.data always refers back to the FileIOContext object itself. */
|
238
|
+
uv_fs_t req;
|
211
239
|
|
212
|
-
|
213
|
-
|
240
|
+
/**
|
241
|
+
* Also a pointer to the FileBufferedChannel, but this is used for
|
242
|
+
* logging purposes inside callbacks (see FBC_DEBUG_FROM_CALLBACK).
|
243
|
+
* This pointer is never set to NULL, may be still, and is never
|
244
|
+
* followed.
|
245
|
+
*/
|
246
|
+
void *logbase;
|
214
247
|
|
215
|
-
|
248
|
+
FileIOContext(FileBufferedChannel *_self)
|
216
249
|
: self(_self),
|
217
250
|
libev(_self->ctx->libev),
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
251
|
+
libuv(_self->ctx->libuv),
|
252
|
+
logbase(_self)
|
253
|
+
{
|
254
|
+
req.type = UV_UNKNOWN_REQ;
|
255
|
+
req.result = -1;
|
256
|
+
req.data = this;
|
257
|
+
}
|
223
258
|
|
224
|
-
virtual ~
|
259
|
+
virtual ~FileIOContext() { }
|
225
260
|
|
226
261
|
void cancel() {
|
227
|
-
|
228
|
-
|
229
|
-
|
262
|
+
if (!isCanceled()) {
|
263
|
+
// uv_cancel() fails if the work is already in progress
|
264
|
+
// or completed, so we set self to NULL as an extra
|
265
|
+
// indicator that this I/O operation is canceled.
|
266
|
+
uv_cancel((uv_req_t *) &req);
|
267
|
+
self = NULL;
|
230
268
|
}
|
231
|
-
canceled.store(true, boost::memory_order_release);
|
232
269
|
}
|
233
270
|
|
271
|
+
/**
|
272
|
+
* Checks whether this I/O operation has been canceled.
|
273
|
+
* Note that the libuv request may not have been canceled
|
274
|
+
* because it was already executing at the time `cancel()`
|
275
|
+
* was called. So after you've checked that `isCanceled()`
|
276
|
+
* returns true, you must also cleanup any potential finished
|
277
|
+
* work in `req`.
|
278
|
+
*/
|
234
279
|
bool isCanceled() const {
|
235
|
-
return
|
236
|
-
|| canceled.load(boost::memory_order_acquire);
|
237
|
-
}
|
238
|
-
|
239
|
-
void eioFinished() {
|
240
|
-
boost::lock_guard<boost::mutex> l(syncher);
|
241
|
-
result = req->result;
|
242
|
-
errcode = req->errorno;
|
243
|
-
req = NULL;
|
280
|
+
return self == NULL || req.result == UV_ECANCELED;
|
244
281
|
}
|
245
282
|
};
|
246
283
|
|
@@ -254,9 +291,9 @@ private:
|
|
254
291
|
* fast case where the consumer can keep up with the writes.
|
255
292
|
* - We improve the clarity of the code by clearly grouping variables
|
256
293
|
* that are only used in the in-file mode.
|
257
|
-
* - While
|
294
|
+
* - While libuv operations are in progress, they hold a smart pointer to the
|
258
295
|
* InFileMode structure, which ensures that the file descriptor that they
|
259
|
-
* operate on stays open until all
|
296
|
+
* operate on stays open until all libuv operations have finished (or until
|
260
297
|
* their cancellation have been acknowledged by their callbacks).
|
261
298
|
*
|
262
299
|
* The variables inside this structure point to different places in the file:
|
@@ -282,6 +319,11 @@ private:
|
|
282
319
|
struct InFileMode {
|
283
320
|
/***** Common state *****/
|
284
321
|
|
322
|
+
/**
|
323
|
+
* The libuv loop associated with the FileBufferedChannel.
|
324
|
+
*/
|
325
|
+
uv_loop_t *libuv;
|
326
|
+
|
285
327
|
/**
|
286
328
|
* The file descriptor of the temp file. It's -1 if the file is being
|
287
329
|
* created.
|
@@ -306,12 +348,12 @@ private:
|
|
306
348
|
|
307
349
|
/**
|
308
350
|
* The write operation that the writer is currently performing. Might be
|
309
|
-
* an `
|
351
|
+
* an `uv_fs_open()`, `uv_fs_write()`, or whatever.
|
310
352
|
*
|
311
353
|
* @invariant
|
312
354
|
* (writerRequest != NULL) == (writerState == WS_CREATING_FILE || writerState == WS_MOVING)
|
313
355
|
*/
|
314
|
-
|
356
|
+
FileIOContext *writerRequest;
|
315
357
|
|
316
358
|
/**
|
317
359
|
* Number of bytes already read from the file by the reader.
|
@@ -331,8 +373,9 @@ private:
|
|
331
373
|
*/
|
332
374
|
boost::int64_t written;
|
333
375
|
|
334
|
-
InFileMode()
|
335
|
-
:
|
376
|
+
InFileMode(uv_loop_t *_libuv)
|
377
|
+
: libuv(_libuv),
|
378
|
+
fd(-1),
|
336
379
|
readRequest(NULL),
|
337
380
|
writerState(WS_INACTIVE),
|
338
381
|
writerRequest(NULL),
|
@@ -344,10 +387,32 @@ private:
|
|
344
387
|
P_ASSERT_EQ(readRequest, 0);
|
345
388
|
P_ASSERT_EQ(writerRequest, 0);
|
346
389
|
if (fd != -1) {
|
347
|
-
|
348
|
-
|
390
|
+
closeFdInBackground();
|
391
|
+
}
|
392
|
+
}
|
393
|
+
|
394
|
+
void closeFdInBackground() {
|
395
|
+
uv_fs_t *req = (uv_fs_t *) malloc(sizeof(uv_fs_t));
|
396
|
+
if (req == NULL) {
|
397
|
+
P_CRITICAL("Cannot close file descriptor for FileBufferedChannel temp file: "
|
398
|
+
"cannot allocate memory for necessary temporary data structure");
|
399
|
+
abort();
|
400
|
+
}
|
401
|
+
|
402
|
+
int result = uv_fs_close(libuv, req, fd, fileClosed);
|
403
|
+
if (result != 0) {
|
404
|
+
P_CRITICAL("Cannot close file descriptor for FileBufferedChannel temp file: "
|
405
|
+
"cannot initiate I/O operation: "
|
406
|
+
<< uv_strerror(result) << " (errno=" << -result << ")");
|
407
|
+
abort();
|
349
408
|
}
|
350
409
|
}
|
410
|
+
|
411
|
+
static void fileClosed(uv_fs_t *req) {
|
412
|
+
P_LOG_FILE_DESCRIPTOR_CLOSE(req->file);
|
413
|
+
uv_fs_req_cleanup(req);
|
414
|
+
free(req);
|
415
|
+
}
|
351
416
|
};
|
352
417
|
|
353
418
|
FileBufferedChannelConfig *config;
|
@@ -642,14 +707,15 @@ private:
|
|
642
707
|
terminateReaderBecauseOfEOF();
|
643
708
|
}
|
644
709
|
|
645
|
-
struct ReadContext: public
|
710
|
+
struct ReadContext: public FileIOContext {
|
646
711
|
MemoryKit::mbuf buffer;
|
647
|
-
|
712
|
+
uv_buf_t uvBuffer;
|
713
|
+
// Smart pointer to keep fd open until libuv operation
|
648
714
|
// is finished.
|
649
715
|
boost::shared_ptr<InFileMode> inFileMode;
|
650
716
|
|
651
717
|
ReadContext(FileBufferedChannel *self)
|
652
|
-
:
|
718
|
+
: FileIOContext(self)
|
653
719
|
{ }
|
654
720
|
};
|
655
721
|
|
@@ -665,57 +731,25 @@ private:
|
|
665
731
|
ReadContext *readContext = new ReadContext(this);
|
666
732
|
readContext->buffer = MemoryKit::mbuf_get(&ctx->mbuf_pool);
|
667
733
|
readContext->inFileMode = inFileMode;
|
734
|
+
readContext->uvBuffer = uv_buf_init(readContext->buffer.start, size);
|
668
735
|
readerState = RS_READING_FROM_FILE;
|
669
736
|
inFileMode->readRequest = readContext;
|
670
|
-
boost::unique_lock<boost::mutex> l(readContext->syncher);
|
671
|
-
readContext->req = eio_read(inFileMode->fd, readContext->buffer.start,
|
672
|
-
size, inFileMode->readOffset, 0, _nextChunkDoneReading, readContext);
|
673
|
-
l.unlock();
|
674
|
-
verifyInvariants();
|
675
|
-
}
|
676
|
-
|
677
|
-
// Since a ReadContext contains an mbuf, we may only destroy it
|
678
|
-
// in the event loop thread.
|
679
|
-
static void destroyReadContext(ReadContext *readContext) {
|
680
|
-
if (readContext->libev->onEventLoopThread()) {
|
681
|
-
destroyReadContext_onEventLoopThread(readContext);
|
682
|
-
} else {
|
683
|
-
readContext->libev->runLater(boost::bind(
|
684
|
-
destroyReadContext_onEventLoopThread,
|
685
|
-
readContext));
|
686
|
-
}
|
687
|
-
}
|
688
737
|
|
689
|
-
|
690
|
-
|
738
|
+
uv_fs_read(ctx->libuv, &readContext->req, inFileMode->fd,
|
739
|
+
&readContext->uvBuffer, 1, inFileMode->readOffset,
|
740
|
+
_nextChunkDoneReading);
|
741
|
+
verifyInvariants();
|
691
742
|
}
|
692
743
|
|
693
|
-
static
|
744
|
+
static void _nextChunkDoneReading(uv_fs_t *req) {
|
694
745
|
ReadContext *readContext = (ReadContext *) req->data;
|
695
|
-
|
746
|
+
uv_fs_req_cleanup(req);
|
696
747
|
if (readContext->isCanceled()) {
|
697
|
-
|
698
|
-
return 0;
|
699
|
-
}
|
700
|
-
|
701
|
-
if (readContext->libev->onEventLoopThread()) {
|
702
|
-
_nextChunkDoneReading_onEventLoopThread(readContext);
|
703
|
-
} else {
|
704
|
-
readContext->libev->runLater(boost::bind(
|
705
|
-
_nextChunkDoneReading_onEventLoopThread,
|
706
|
-
readContext));
|
707
|
-
}
|
708
|
-
return 0;
|
709
|
-
}
|
710
|
-
|
711
|
-
static void _nextChunkDoneReading_onEventLoopThread(ReadContext *readContext) {
|
712
|
-
if (readContext->isCanceled()) {
|
713
|
-
destroyReadContext(readContext);
|
748
|
+
delete readContext;
|
714
749
|
return;
|
715
750
|
}
|
716
751
|
|
717
|
-
|
718
|
-
self->nextChunkDoneReading(readContext);
|
752
|
+
readContext->self->nextChunkDoneReading(readContext);
|
719
753
|
}
|
720
754
|
|
721
755
|
void nextChunkDoneReading(ReadContext *readContext) {
|
@@ -724,13 +758,12 @@ private:
|
|
724
758
|
FBC_DEBUG("Reader: done reading chunk");
|
725
759
|
P_ASSERT_EQ(readerState, RS_READING_FROM_FILE);
|
726
760
|
verifyInvariants();
|
727
|
-
int fd = readContext->result;
|
728
|
-
int errcode = readContext->errcode;
|
729
761
|
MemoryKit::mbuf buffer(boost::move(readContext->buffer));
|
730
|
-
|
762
|
+
delete readContext;
|
731
763
|
inFileMode->readRequest = NULL;
|
732
764
|
|
733
|
-
if (
|
765
|
+
if (readContext->req.result >= 0) {
|
766
|
+
int fd = readContext->req.result;
|
734
767
|
unsigned int generation = this->generation;
|
735
768
|
|
736
769
|
assert(fd <= inFileMode->written);
|
@@ -757,6 +790,7 @@ private:
|
|
757
790
|
terminateReaderBecauseOfEOF();
|
758
791
|
}
|
759
792
|
} else {
|
793
|
+
int errcode = -readContext->req.result;
|
760
794
|
setError(errcode, __FILE__, __LINE__);
|
761
795
|
}
|
762
796
|
}
|
@@ -800,7 +834,7 @@ private:
|
|
800
834
|
|
801
835
|
FBC_DEBUG("Switching to in-file mode");
|
802
836
|
mode = IN_FILE_MODE;
|
803
|
-
inFileMode = boost::make_shared<InFileMode>();
|
837
|
+
inFileMode = boost::make_shared<InFileMode>(ctx->libuv);
|
804
838
|
createBufferFile();
|
805
839
|
}
|
806
840
|
|
@@ -826,11 +860,11 @@ private:
|
|
826
860
|
|
827
861
|
/***** File creator *****/
|
828
862
|
|
829
|
-
struct FileCreationContext: public
|
863
|
+
struct FileCreationContext: public FileIOContext {
|
830
864
|
string path;
|
831
865
|
|
832
866
|
FileCreationContext(FileBufferedChannel *self)
|
833
|
-
:
|
867
|
+
: FileIOContext(self)
|
834
868
|
{ }
|
835
869
|
};
|
836
870
|
|
@@ -847,41 +881,28 @@ private:
|
|
847
881
|
inFileMode->writerState = WS_CREATING_FILE;
|
848
882
|
inFileMode->writerRequest = fcContext;
|
849
883
|
|
850
|
-
boost::lock_guard<boost::mutex> l(fcContext->syncher);
|
851
884
|
if (config->delayInFileModeSwitching == 0) {
|
852
885
|
FBC_DEBUG("Writer: creating file " << fcContext->path);
|
853
|
-
|
854
|
-
O_RDWR | O_CREAT | O_EXCL,
|
855
|
-
|
886
|
+
int result = uv_fs_open(ctx->libuv, &fcContext->req,
|
887
|
+
fcContext->path.c_str(), O_RDWR | O_CREAT | O_EXCL,
|
888
|
+
0600, _bufferFileCreated);
|
889
|
+
if (result != 0) {
|
890
|
+
fcContext->req.result = result;
|
891
|
+
ctx->libev->runLater(boost::bind(_bufferFileCreated,
|
892
|
+
&fcContext->req));
|
893
|
+
}
|
856
894
|
} else {
|
857
895
|
FBC_DEBUG("Writer: delaying in-file mode switching for " <<
|
858
896
|
config->delayInFileModeSwitching << "ms");
|
859
|
-
|
860
|
-
(
|
861
|
-
0, _bufferFileDoneDelaying, fcContext);
|
862
|
-
}
|
863
|
-
}
|
864
|
-
|
865
|
-
static int _bufferFileDoneDelaying(eio_req *req) {
|
866
|
-
FileCreationContext *fcContext = static_cast<FileCreationContext *>(req->data);
|
867
|
-
fcContext->eioFinished();
|
868
|
-
if (fcContext->isCanceled()) {
|
869
|
-
delete fcContext;
|
870
|
-
return 0;
|
897
|
+
ctx->libev->runAfter(config->delayInFileModeSwitching,
|
898
|
+
boost::bind(_bufferFileDoneDelaying, fcContext));
|
871
899
|
}
|
872
|
-
|
873
|
-
if (fcContext->libev->onEventLoopThread()) {
|
874
|
-
_bufferFileDoneDelaying_onEventLoopThread(fcContext);
|
875
|
-
} else {
|
876
|
-
fcContext->libev->runLater(boost::bind(
|
877
|
-
_bufferFileDoneDelaying_onEventLoopThread,
|
878
|
-
fcContext));
|
879
|
-
}
|
880
|
-
return 0;
|
881
900
|
}
|
882
901
|
|
883
|
-
static void
|
902
|
+
static void _bufferFileDoneDelaying(FileCreationContext *fcContext) {
|
884
903
|
if (fcContext->isCanceled()) {
|
904
|
+
// We don't cleanup fcContext->req here because we didn't
|
905
|
+
// start a libuv request.
|
885
906
|
delete fcContext;
|
886
907
|
return;
|
887
908
|
}
|
@@ -891,72 +912,52 @@ private:
|
|
891
912
|
}
|
892
913
|
|
893
914
|
void bufferFileDoneDelaying(FileCreationContext *fcContext) {
|
894
|
-
boost::lock_guard<boost::mutex> l(fcContext->syncher);
|
895
915
|
FBC_DEBUG("Writer: done delaying in-file mode switching. "
|
896
916
|
"Creating file: " << fcContext->path);
|
897
|
-
|
898
|
-
O_RDWR | O_CREAT | O_EXCL,
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
FileCreationContext *fcContext = static_cast<FileCreationContext *>(req->data);
|
904
|
-
fcContext->eioFinished();
|
905
|
-
if (fcContext->isCanceled()) {
|
906
|
-
if (req->result != -1) {
|
907
|
-
FileBufferedChannel *self = fcContext->self;
|
908
|
-
FBC_DEBUG_FROM_STATIC("Writer: creation of file " << fcContext->path <<
|
909
|
-
"canceled. Deleting file in the background");
|
910
|
-
eio_unlink(fcContext->path.c_str(), 0, bufferFileUnlinked, fcContext);
|
911
|
-
eio_close(req->result, 0, NULL, NULL);
|
912
|
-
} else {
|
913
|
-
delete fcContext;
|
914
|
-
}
|
915
|
-
return 0;
|
917
|
+
int result = uv_fs_open(ctx->libuv, &fcContext->req,
|
918
|
+
fcContext->path.c_str(), O_RDWR | O_CREAT | O_EXCL,
|
919
|
+
0600, _bufferFileCreated);
|
920
|
+
if (result != 0) {
|
921
|
+
fcContext->req.result = result;
|
922
|
+
_bufferFileCreated(&fcContext->req);
|
916
923
|
}
|
917
|
-
|
918
|
-
if (fcContext->libev->onEventLoopThread()) {
|
919
|
-
_bufferFileCreated_onEventLoopThread(fcContext);
|
920
|
-
} else {
|
921
|
-
fcContext->libev->runLater(boost::bind(
|
922
|
-
_bufferFileCreated_onEventLoopThread,
|
923
|
-
fcContext));
|
924
|
-
}
|
925
|
-
return 0;
|
926
924
|
}
|
927
925
|
|
928
|
-
static void
|
926
|
+
static void _bufferFileCreated(uv_fs_t *req) {
|
927
|
+
FileCreationContext *fcContext = static_cast<FileCreationContext *>(req->data);
|
928
|
+
uv_fs_req_cleanup(req);
|
929
929
|
if (fcContext->isCanceled()) {
|
930
|
-
if (
|
931
|
-
|
932
|
-
|
930
|
+
if (req->result >= 0) {
|
931
|
+
FBC_DEBUG_FROM_CALLBACK(fcContext,
|
932
|
+
"Writer: creation of file " << fcContext->path <<
|
933
933
|
"canceled. Deleting file in the background");
|
934
|
-
|
935
|
-
|
934
|
+
closeBufferFileInBackground(fcContext);
|
935
|
+
// Will take care of deleting fcContext
|
936
|
+
unlinkBufferFileInBackground(fcContext);
|
936
937
|
} else {
|
937
938
|
delete fcContext;
|
938
939
|
}
|
939
940
|
return;
|
940
941
|
}
|
941
942
|
|
942
|
-
|
943
|
-
self->bufferFileCreated(fcContext);
|
943
|
+
fcContext->self->bufferFileCreated(fcContext);
|
944
944
|
}
|
945
945
|
|
946
946
|
void bufferFileCreated(FileCreationContext *fcContext) {
|
947
947
|
P_ASSERT_EQ(inFileMode->writerState, WS_CREATING_FILE);
|
948
948
|
verifyInvariants();
|
949
|
-
int fd = fcContext->result;
|
950
|
-
int errcode = fcContext->errcode;
|
951
949
|
inFileMode->writerRequest = NULL;
|
952
950
|
|
953
|
-
if (
|
951
|
+
if (fcContext->req.result >= 0) {
|
954
952
|
FBC_DEBUG("Writer: file created. Deleting file in the background");
|
955
|
-
P_LOG_FILE_DESCRIPTOR_OPEN4(
|
956
|
-
|
957
|
-
inFileMode->fd =
|
953
|
+
P_LOG_FILE_DESCRIPTOR_OPEN4(fcContext->req.result, __FILE__, __LINE__,
|
954
|
+
"FileBufferedChannel buffer file");
|
955
|
+
inFileMode->fd = fcContext->req.result;
|
956
|
+
// Will take care of deleting fcContext
|
957
|
+
unlinkBufferFileInBackground(fcContext);
|
958
958
|
moveNextBufferToFile();
|
959
959
|
} else {
|
960
|
+
int errcode = -fcContext->req.result;
|
960
961
|
delete fcContext;
|
961
962
|
if (errcode == EEXIST) {
|
962
963
|
FBC_DEBUG("Writer: file already exists, retrying");
|
@@ -969,38 +970,97 @@ private:
|
|
969
970
|
}
|
970
971
|
}
|
971
972
|
|
972
|
-
static
|
973
|
+
static void closeBufferFileInBackground(FileCreationContext *fcContext) {
|
974
|
+
// Do not use fcContext->self in here. This method may be called
|
975
|
+
// when the I/O operation is already canceled.
|
976
|
+
|
977
|
+
assert(fcContext->req.result >= 0);
|
978
|
+
|
979
|
+
uv_fs_t *closeReq = (uv_fs_t *) malloc(sizeof(uv_fs_t));
|
980
|
+
if (closeReq == NULL) {
|
981
|
+
FBC_CRITICAL_FROM_CALLBACK(fcContext,
|
982
|
+
"Cannot close file descriptor for " << fcContext->path
|
983
|
+
<< ": cannot allocate memory for necessary temporary data structure");
|
984
|
+
abort();
|
985
|
+
}
|
986
|
+
|
987
|
+
int result = uv_fs_close(fcContext->libuv, closeReq, fcContext->req.result,
|
988
|
+
bufferFileClosed);
|
989
|
+
if (result != 0) {
|
990
|
+
FBC_CRITICAL_FROM_CALLBACK(fcContext,
|
991
|
+
"Cannot close file descriptor for " << fcContext->path
|
992
|
+
<< ": cannot initiate I/O operation: "
|
993
|
+
<< uv_strerror(result) << " (errno=" << -result << ")");
|
994
|
+
abort();
|
995
|
+
}
|
996
|
+
}
|
997
|
+
|
998
|
+
static void unlinkBufferFileInBackground(FileCreationContext *fcContext) {
|
999
|
+
// Nobody will cancel this unlink operation. We set self to NULL
|
1000
|
+
// here as a warning that we should not use the backpointer.
|
1001
|
+
fcContext->self = NULL;
|
1002
|
+
|
1003
|
+
uv_fs_t *unlinkReq = (uv_fs_t *) malloc(sizeof(uv_fs_t));
|
1004
|
+
if (unlinkReq == NULL) {
|
1005
|
+
FBC_ERROR_FROM_CALLBACK(fcContext,
|
1006
|
+
"Cannot delete " << fcContext->path <<
|
1007
|
+
": cannot allocate memory for necessary temporary data structure");
|
1008
|
+
delete fcContext;
|
1009
|
+
} else {
|
1010
|
+
unlinkReq->data = fcContext;
|
1011
|
+
int result = uv_fs_unlink(fcContext->libuv, unlinkReq, fcContext->path.c_str(),
|
1012
|
+
bufferFileUnlinked);
|
1013
|
+
if (result != 0) {
|
1014
|
+
FBC_ERROR_FROM_CALLBACK(fcContext,
|
1015
|
+
"Cannot delete " << fcContext->path << ": cannot initiate I/O operation: "
|
1016
|
+
<< uv_strerror(result) << " (errno=" << -result << ")");
|
1017
|
+
free(unlinkReq);
|
1018
|
+
delete fcContext;
|
1019
|
+
}
|
1020
|
+
}
|
1021
|
+
}
|
1022
|
+
|
1023
|
+
static void bufferFileUnlinked(uv_fs_t *req) {
|
973
1024
|
FileCreationContext *fcContext = static_cast<FileCreationContext *>(req->data);
|
974
|
-
|
1025
|
+
assert(fcContext->self == NULL);
|
975
1026
|
|
976
|
-
if (
|
1027
|
+
if (req->result == UV_ECANCELED) {
|
1028
|
+
uv_fs_req_cleanup(req);
|
977
1029
|
delete fcContext;
|
978
|
-
return
|
1030
|
+
return;
|
979
1031
|
}
|
980
1032
|
|
981
|
-
if (req->result
|
982
|
-
|
1033
|
+
if (req->result >= 0) {
|
1034
|
+
FBC_DEBUG_FROM_CALLBACK(fcContext,
|
1035
|
+
"Writer: file " << fcContext->path << " deleted");
|
983
1036
|
} else {
|
984
|
-
|
985
|
-
":
|
1037
|
+
FBC_DEBUG_FROM_CALLBACK(fcContext,
|
1038
|
+
"Writer: failed to delete " << fcContext->path <<
|
1039
|
+
": " << uv_strerror(req->result) << " (errno=" << -req->result << ")");
|
986
1040
|
}
|
987
1041
|
|
1042
|
+
uv_fs_req_cleanup(req);
|
988
1043
|
delete fcContext;
|
989
|
-
|
1044
|
+
}
|
1045
|
+
|
1046
|
+
static void bufferFileClosed(uv_fs_t *req) {
|
1047
|
+
uv_fs_req_cleanup(req);
|
1048
|
+
free(req);
|
990
1049
|
}
|
991
1050
|
|
992
1051
|
|
993
1052
|
/***** Mover *****/
|
994
1053
|
|
995
|
-
struct MoveContext: public
|
996
|
-
// Smart pointer to keep fd open until
|
1054
|
+
struct MoveContext: public FileIOContext {
|
1055
|
+
// Smart pointer to keep fd open until libuv operation
|
997
1056
|
// is finished.
|
998
1057
|
boost::shared_ptr<InFileMode> inFileMode;
|
999
1058
|
MemoryKit::mbuf buffer;
|
1059
|
+
uv_buf_t uvBuffer;
|
1000
1060
|
size_t written;
|
1001
1061
|
|
1002
1062
|
MoveContext(FileBufferedChannel *self)
|
1003
|
-
:
|
1063
|
+
: FileIOContext(self)
|
1004
1064
|
{ }
|
1005
1065
|
};
|
1006
1066
|
|
@@ -1026,61 +1086,32 @@ private:
|
|
1026
1086
|
moveContext->inFileMode = inFileMode;
|
1027
1087
|
moveContext->buffer = peekBuffer();
|
1028
1088
|
moveContext->written = 0;
|
1089
|
+
moveContext->uvBuffer = uv_buf_init(moveContext->buffer.start,
|
1090
|
+
moveContext->buffer.size());
|
1029
1091
|
|
1030
1092
|
inFileMode->writerState = WS_MOVING;
|
1031
1093
|
inFileMode->writerRequest = moveContext;
|
1032
|
-
|
1033
|
-
|
1034
|
-
moveContext->buffer.start,
|
1035
|
-
moveContext->buffer.size(),
|
1094
|
+
int result = uv_fs_write(ctx->libuv, &moveContext->req, inFileMode->fd,
|
1095
|
+
&moveContext->uvBuffer, 1,
|
1036
1096
|
inFileMode->readOffset + inFileMode->written,
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
// Since a MoveContext contains an mbuf, we may only destroy it
|
1043
|
-
// in the event loop thread.
|
1044
|
-
static void destroyMoveContext(MoveContext *moveContext) {
|
1045
|
-
if (moveContext->libev->onEventLoopThread()) {
|
1046
|
-
destroyMoveContext_onEventLoopThread(moveContext);
|
1047
|
-
} else {
|
1048
|
-
moveContext->libev->runLater(boost::bind(
|
1049
|
-
destroyMoveContext_onEventLoopThread,
|
1050
|
-
moveContext));
|
1097
|
+
_bufferWrittenToFile);
|
1098
|
+
if (result != 0) {
|
1099
|
+
moveContext->req.result = result;
|
1100
|
+
ctx->libev->runLater(boost::bind(_bufferWrittenToFile,
|
1101
|
+
&moveContext->req));
|
1051
1102
|
}
|
1103
|
+
verifyInvariants();
|
1052
1104
|
}
|
1053
1105
|
|
1054
|
-
static void
|
1055
|
-
delete moveContext;
|
1056
|
-
}
|
1057
|
-
|
1058
|
-
static int _bufferWrittenToFile(eio_req *req) {
|
1106
|
+
static void _bufferWrittenToFile(uv_fs_t *req) {
|
1059
1107
|
MoveContext *moveContext = static_cast<MoveContext *>(req->data);
|
1060
|
-
|
1108
|
+
uv_fs_req_cleanup(req);
|
1061
1109
|
if (moveContext->isCanceled()) {
|
1062
|
-
|
1063
|
-
return 0;
|
1064
|
-
}
|
1065
|
-
|
1066
|
-
if (moveContext->libev->onEventLoopThread()) {
|
1067
|
-
_bufferWrittenToFile_onEventLoopThread(moveContext);
|
1068
|
-
} else {
|
1069
|
-
moveContext->libev->runLater(boost::bind(
|
1070
|
-
_bufferWrittenToFile_onEventLoopThread,
|
1071
|
-
moveContext));
|
1072
|
-
}
|
1073
|
-
return 0;
|
1074
|
-
}
|
1075
|
-
|
1076
|
-
static void _bufferWrittenToFile_onEventLoopThread(MoveContext *moveContext) {
|
1077
|
-
if (moveContext->isCanceled()) {
|
1078
|
-
destroyMoveContext(moveContext);
|
1110
|
+
delete moveContext;
|
1079
1111
|
return;
|
1080
1112
|
}
|
1081
1113
|
|
1082
|
-
|
1083
|
-
self->bufferWrittenToFile(moveContext);
|
1114
|
+
moveContext->self->bufferWrittenToFile(moveContext);
|
1084
1115
|
}
|
1085
1116
|
|
1086
1117
|
void bufferWrittenToFile(MoveContext *moveContext) {
|
@@ -1089,8 +1120,8 @@ private:
|
|
1089
1120
|
assert(!peekBuffer().empty());
|
1090
1121
|
verifyInvariants();
|
1091
1122
|
|
1092
|
-
if (moveContext->result
|
1093
|
-
moveContext->written += moveContext->result;
|
1123
|
+
if (moveContext->req.result >= 0) {
|
1124
|
+
moveContext->written += moveContext->req.result;
|
1094
1125
|
assert(moveContext->written <= moveContext->buffer.size());
|
1095
1126
|
|
1096
1127
|
if (moveContext->written == moveContext->buffer.size()) {
|
@@ -1106,29 +1137,34 @@ private:
|
|
1106
1137
|
if (generation != this->generation || mode >= ERROR) {
|
1107
1138
|
// buffersFlushedCallback deinitialized this object, or callback
|
1108
1139
|
// called a method that encountered an error.
|
1109
|
-
|
1140
|
+
delete moveContext;
|
1110
1141
|
return;
|
1111
1142
|
}
|
1112
1143
|
|
1113
1144
|
inFileMode->writerRequest = NULL;
|
1114
|
-
|
1145
|
+
delete moveContext;
|
1115
1146
|
moveNextBufferToFile();
|
1116
1147
|
} else {
|
1117
1148
|
FBC_DEBUG("Writer: move incomplete, proceeding " <<
|
1118
1149
|
"with writing rest of buffer");
|
1119
|
-
|
1120
|
-
moveContext->req = eio_write(inFileMode->fd,
|
1150
|
+
moveContext->uvBuffer = uv_buf_init(
|
1121
1151
|
moveContext->buffer.start + moveContext->written,
|
1122
|
-
moveContext->buffer.size() - moveContext->written
|
1152
|
+
moveContext->buffer.size() - moveContext->written);
|
1153
|
+
int result = uv_fs_write(ctx->libuv, &moveContext->req,
|
1154
|
+
inFileMode->fd, &moveContext->uvBuffer, 1,
|
1123
1155
|
inFileMode->readOffset + inFileMode->written,
|
1124
|
-
|
1125
|
-
|
1156
|
+
_bufferWrittenToFile);
|
1157
|
+
if (result != 0) {
|
1158
|
+
moveContext->req.result = result;
|
1159
|
+
ctx->libev->runLater(boost::bind(_bufferWrittenToFile,
|
1160
|
+
&moveContext->req));
|
1161
|
+
}
|
1126
1162
|
verifyInvariants();
|
1127
1163
|
}
|
1128
1164
|
} else {
|
1129
1165
|
FBC_DEBUG("Writer: file write failed");
|
1130
|
-
int errcode = moveContext->
|
1131
|
-
|
1166
|
+
int errcode = -moveContext->req.result;
|
1167
|
+
delete moveContext;
|
1132
1168
|
inFileMode->writerRequest = NULL;
|
1133
1169
|
inFileMode->writerState = WS_TERMINATED;
|
1134
1170
|
setError(errcode, __FILE__, __LINE__);
|