Commit Graph
100 Commits
Author SHA1 Message Date
Max Romanov 7ffc617ae8 Supporting platforms without sendfile() implementation.
This is a quick and dirty sendfile() replacement.

This closes #452 PR on GitHub.
2020-08-17 12:28:48 +03:00
Max Romanov 4ac7a6f55f Style: changing preprocessor directives.
Using #if directives instead of #ifdef the same way as in other places.
2020-08-17 12:28:40 +03:00
Max Romanov b04b5ce430 Fixing router assertion in result of application prefork error.
Buffer for application prefork request allocated from temp conf mem_pool.
If error response from main process received before buffer completion handler,
temp conf mem_pool destroyed and router may crash in completion handler.

Assertion "src/nxt_buf.c:208 assertion failed: data == b->parent" triggered
when NXT_DEBUG_ALLOC enabled in configure.

This patch disables completion handler and memory allocated for buffer
released with memory pool.
2020-08-13 16:08:38 +03:00
Max Romanov 09685e2b41 Responding with error in case of first process start failure.
After shared application port introducing, request queue in router was
removed and requests may stuck forever waiting for another process start.
2020-08-12 15:25:29 +03:00
Max Romanov 2136eb411c Fixing issues found by static analyzer. 2020-08-12 13:37:49 +03:00
Max Romanov fd2c01c58f Fixing return value initialization. 2020-08-11 21:48:46 +03:00
Max Romanov f147943f63 Style fixes for 2 file descriptors transfer over port.
Two consecutive fd and fd2 fields replaced with array.
2020-08-11 21:48:27 +03:00
Max Romanov acb0cca49d Moving file descriptor blocking to libunit.
The default libunit behavior relies on blocking the recv() call for port file
descriptors, which an application may override if needed.  For external
applications, port file descriptors were toggled to blocking mode before the
exec() call.  If the exec() call failed, descriptor remained blocked, so the
process hanged while trying to read from it.

This patch moves file descriptor mode switch inside libunit.
2020-08-11 21:48:16 +03:00
Max Romanov 8cf522bf2d Wrapping close() call in libunit for logging. 2020-08-11 19:20:36 +03:00
Max Romanov e227fc9e62 Introducing application and port shared memory queues.
The goal is to minimize the number of syscalls needed to deliver a message.
2020-08-11 19:20:34 +03:00
Max Romanov a82cf4ffb6 Circular queues implementations and a test.
- naive circular queue, described in the article "A Scalable, Portable, and
 Memory-Efficient Lock-Free FIFO Queue" by Ruslan Nikolaev:
https://drops.dagstuhl.de/opus/volltexte/2019/11335/pdf/LIPIcs-DISC-2019-28.pdf
- circular queue, proposed by Valentin Bartenev in the "Unit router application
IPC" design draft
2020-08-11 19:20:32 +03:00
Max Romanov a1e9df2aef Port message extended to transfer 2 file descriptors. 2020-08-11 19:20:30 +03:00
Max Romanov 72475ee11c Made router port message handlers into static functions.
Mostly harmless.
2020-08-11 19:20:28 +03:00
Max Romanov 496f41c134 Tests: reducing the number of generated applications.
Each application initializes a shared port with 2 file descriptors, so the test
fails because the router reaches the open files limit.
2020-08-11 19:20:25 +03:00
Max Romanov bab4a9e9f2 Tests: skipping idle zero timeout.
This is a temporary solution after the 'shared port' patch.  The application
process becomes idle immediately after creation.  Even if it starts processing
a request (without acknowledging it yet), it is stopped by the router because
an 'out-of-idle-time' event occurs.
2020-08-11 19:20:23 +03:00
Max Romanov f4a118f84a Adding debug messages to catch process management issues. 2020-08-11 19:20:20 +03:00
Max Romanov 2f3d27fa22 Process structures refactoring in runtime and libunit.
Generic process-to-process shared memory exchange is no more required.  Here,
it is transformed into a router-to-application pattern.  The outgoing shared
memory segments collection is now the property of the application structure.
The applications connect to the router only, and the process only needs to group
the ports.
2020-08-11 19:20:17 +03:00
Max Romanov 8359560612 Introducing the shared application port.
This is the port shared between all application processes which use it to pass
requests for processing.  Using it significantly simplifies the request
processing code in the router.  The drawback is 2 more file descriptors per each
configured application and more complex libunit message wait/read code.
2020-08-11 19:20:15 +03:00
Max Romanov 6e31d6cd39 Changing router to application shared memory exchange protocol.
The application process needs to request the shared memory segment from the
router instead of the latter pushing the segment before sending a request to
the application.  This is required to simplify the communication between the
router and the application and to prepare the router for using the application
shared port and then the queue.
2020-08-11 19:20:13 +03:00
Max Romanov 3cbc22a6dc Changing router to application port exchange protocol.
The application process needs to request the port from the router instead of the
latter pushing the port before sending a request to the application.  This is
required to simplify the communication between the router and the application
and to prepare the router to use the application shared port and then the queue.
2020-08-11 19:20:10 +03:00
Max Romanov bf647588ff Adding a reference counter to the libunit port structure.
The goal is to minimize the number of (pid, id) to port hash lookups which
require a library mutex lock.  The response port is found once per request,
while the read port is initialized at startup.
2020-08-11 19:20:06 +03:00
Max Romanov ec3389b63b Libunit refactoring: port management.
- Changed the port management callbacks to notifications, which e. g. avoids
the need to call the libunit function
- Added context and library instance reference counts for a safer resource
release
- Added the router main port initialization
2020-08-11 19:19:55 +03:00
Max Romanov 3a721e1d96 Fixing leaked configuration objects.
If there are no listen sockets, the router configuration usage counter
remains 0 and never decreases.  The only moment to release a configuration is
right after a configuration update.
2020-08-09 10:26:19 +03:00
Max Romanov 0f3abebd01 Fixing connection remote sockaddr leakage.
Earlier patch 1bf971f83571 fixes connection leakage.  But connection
free requires separate remote sockaddr release.
2020-08-09 10:22:05 +03:00
Max Romanov 375cbc2cc4 Node.js: correct port data memory release.
According to libuv documentation, uv_poll_t memory should be released
in a callback function passed to uv_close().  Otherwise, the Node.js application
process may crash at exit.
2020-08-07 15:06:24 +03:00
Max Romanov 78fd04adcf Fixing listen event connection leakage.
A connection object is allocated in advance for each listen event object to be
used for the established connection.  This connection needs to be freed when the
listen event is destroyed.
2020-08-07 15:06:18 +03:00
Max Romanov c617480eef Using plain shared memory for configuration pass.
There is no restrictions on configration size and using segmented shared memory
only doubles memory usage because to parse configration on router side,
it needs to be 'plain' e. g. located in single continous memory buffer.
2020-07-25 11:06:32 +03:00
Max Romanov 762511c510 Fixing request_app_link reference counting.
Racing conditions reproduced periodically on test_python_process_switch.
2020-07-23 14:25:46 +03:00
Max Romanov 9641fb0ef1 Fixing various router crashes on exit caused by runtime pool free.
Currently, the router exits without waiting for the worker threads to stop.
There is a short gap between the runtime memory pool's free and the exit, during
which a worker thread may try to access a runtime structure.  In turn, this may
cause a crash.  For now, it is better to keep this memory allocated.
2020-07-23 14:25:21 +03:00
Max Romanov d3c8d62280 PHP: using nxt_unit_default_init() for module structure init.
Using this function in all language modules helps to avoid code duplication
and reduce the size of future patches.
2020-07-23 14:25:12 +03:00
Max Romanov 137c1e736f Fixing main and application port structs file descriptor init.
Correct value for non-initialized file descriptor is -1, because most of the
checks in libunit compares file descriptor with -1 before performing an
action.  Using 0 as default value, may cause to close file descriptor #0, this
may affect application logic.

It is not required to list this patch in changelog because impact is not seen
by end users.
2020-07-23 14:24:55 +03:00
Max Romanov fa696569f9 PHP: removing assertion to fix build on macOS.
The nxt_assert macro uses nxt_thread_context, which caused the following linker
error when using it in the library:

ld: illegal thread local variable reference to regular symbol
_nxt_thread_context for architecture x86_64
2020-07-23 14:24:16 +03:00
Max Romanov 661c223eda Tests: switching stdout to blocking before printing log.
This is another attempt to fix the following error message:
BlockingIOError: [Errno 11] write could not complete without blocking
2020-07-22 10:05:10 +03:00
Max Romanov ef71948196 Fixing buffer overflow check in discovery.
Incorrect check prevents Unit to start without modules.

This issue was introduced in 4a3ec07f4b19.
2020-07-22 10:04:57 +03:00
Max Romanov aacf11152c Moving nxt_stream_ident to shared memory.
This aims to avoid stream id clashes after router restart.
2020-05-28 12:41:00 +03:00
Max Romanov de368f033d Added NULL check for engine->port.
This is required to handle REMOVE_PID messages if router engine
initialization is incomplete.
2020-05-28 12:40:54 +03:00
Max Romanov 89b1e88f8f Closing unsent file descriptors from port queue.
After a process exits, all ports linked to it from other processes
should be closed.  All unsent file descriptors in port queue, marked as
"close after send", should be closed to avoid resource leakage.
2020-05-28 12:40:49 +03:00
Max Romanov 3ec72362b9 Waiting for router instead of reporting to user on config update. 2020-05-12 16:25:24 +03:00
Max Romanov 50f9816daa Blocking config change when applying the initial router config. 2020-05-12 16:25:16 +03:00
Max Romanov 6bda9b5eeb Using malloc/free for the http fields hash.
This is required due to lack of a graceful shutdown: there is a small gap
between the runtime's memory pool release and router process's exit. Thus, a
worker thread may start processing a request between these two operations,
which may result in an http fields hash access and subsequent crash.

To simplify issue reproduction, it makes sense to add a 2 sec sleep before
exit() in nxt_runtime_exit().
2020-04-16 17:09:23 +03:00
Max Romanov 9a422b8984 Completing chained shared memory buffers.
After 41331471eee7 completion handlers should complete next buffer in chain.
Otherwise buffer memory may leak.

Thanks to Peter Tkatchenko for reporing the issue and testing fixes.
2020-04-14 16:11:13 +03:00
Max Romanov 58cc13ab29 Resolving a racing condition while adding ports on the app's side.
An earlier attempt (ad6265786871) to resolve this condition on the
router's side added a new issue: the app could get a request before
acquiring a port.
2020-04-10 16:21:58 +03:00
Max Romanov ce53d6bdb1 Node.js: fixing Server.listen() method.
This is required for Express framework compatibility.

This closes #418 issue on GitHub.
2020-04-08 14:44:53 +03:00
Max Romanov 792ef9d3c7 Fixing 'find & add' racing condition in connected ports hash.
Missing error log messages added.
2020-04-06 16:52:11 +03:00
Max Romanov 0935630cba Fixing application process infinite loop.
Main process exiting before app process init may have caused hanging.
2020-03-30 14:18:51 +03:00
Max Romanov ab7b42a072 Handling change file message in libunit.
This is required for proper log file rotation action.
2020-03-30 14:18:41 +03:00
Max Romanov 82b899b136 Attributing libunit logging function for arguments validation. 2020-03-30 14:08:20 +03:00
Max Romanov 59e06e4910 Completing buffers immediately
This fixes crash introduced in 039b00e32e3d.
2020-03-19 22:04:43 +03:00
Max Romanov c26fbbe53a Completing request header buffers to avoid memory leak.
Before this fix, only persistent connection request buffers were completed.

This issue was introduced in dc403927ab0b.
2020-03-19 20:43:35 +03:00
Max Romanov c6f9ca79e6 Fixing body fd access racing condition.
To avoid closing the body fd prematurely, the fd value is moved from
the request struct to the app link.  The body fd should not be closed
immediately after the request is sent to the application due to possible
request rescheduling.
2020-03-17 14:44:11 +03:00
Max Romanov efbcd517fc Checking sendfile() availability in configure.
Removing SF_NODISKIO flag for FreeBSD sendfile() check because it
is not used yet and to support DragonFlyBSD.

This closes #414 issue on GitHub.
2020-03-17 14:44:06 +03:00
Max Romanov 5296be0b82 Using disk file to store large request body.
This closes #386 on GitHub.
2020-03-12 17:54:29 +03:00
Max Romanov 08b65721e2 Moving request memory pool retain call after RPC data allocation.
If the call is done only after a successful RPC data allocation, its
corresponding release call is not missed, which avoids a potential leak.
2020-03-12 17:54:24 +03:00
Max Romanov 0b5aabfc3f Checking Content-Length value right after header parse.
The check was moved from the request body read stage.
2020-03-12 17:54:19 +03:00
Max Romanov f3e6726098 Tests: added Python input readline and iterator tests. 2020-03-12 17:54:15 +03:00
Max Romanov 7c4db34b88 Python: implementing input readline and line iterator. 2020-03-12 17:54:11 +03:00
Max Romanov 2454dfe876 Introducing readline function in libunit.
Ruby and Java modules now use this function instead of own
implementations.
2020-03-12 17:54:05 +03:00
Max Romanov 9e295fa314 Fixing request_app_link reference counting for delayed requests.
Router built with debug may stop with assertion during stalled requests
re-schedule.  This was caused by missing reference counting increment
before nxt_router_port_select() call.
2020-03-03 18:28:26 +03:00
Max Romanov c74f3a6c56 Java: fixing Spring applications start.
This closes #403 issue on GitHub.
2020-03-03 18:28:20 +03:00
Max Romanov 004ab48a9e Node.js: fixing x86 warning about the signed/unsigned comparison. 2020-03-03 18:28:16 +03:00
Max Romanov 81b39d0b35 Tests: fixing Python 3.8.1 errors on Mac.
- "Can't pickle local object ..."
- "if __name__ == '__main__':" pattern required for multiprocessing
2020-02-04 11:39:34 +03:00
Max Romanov 7c38650cd1 Removing duplicate macro definitions.
This issue was introduced in 2c7f79bf0a1f.
2020-02-04 11:39:16 +03:00
Max Romanov 8eba2e5c3d Initializing local buffer ctx_impl field for correct release.
Uninitialized ctx_impl field may cause crash in application process.

To reproduce the issue, need to trigger shared memory buffer send error on
application side.  In our case, send error caused by router process crash.

This issue was introduced in 2c7f79bf0a1f.
2020-02-03 11:21:21 +03:00
Max Romanov 7ea9ebc55a Fixed req_app_link reference counting on cancellation.
Re-scheduled req_app_link structures should have use_count exactly equal
to the number of references from the application and port list.  However,
there's one extra usage decrement that occurs after the req_app_link is
created because the use_count is initialised as 1.

This patch removes all excess instances of the usage decrement that caused
preliminary req_app_link release and router process crash.

To reproduce the issue need to cause request rescheduling between 2 app
processes.

This issue was introduced in 61e9f23a566d.
2020-02-03 11:20:59 +03:00
Max Romanov 8c0f2cebf5 Storing pointer to next buffer in chain before free the buffer.
This is required to avoid dereference of freed memory.

Found by Coverity (CID 353372).
2020-02-03 11:14:14 +03:00
Max Romanov 51120e06e3 Added missing stream argument to error message.
Found by Coverity (CID 353386).
2020-02-03 11:14:06 +03:00
Max Romanov 224549a578 Freeing memory allocated for engine structure in case of error.
Found by Coverity (CID 353389).
2020-02-03 11:13:55 +03:00
Max Romanov 4024b18bcc Go: adding main configure CFLAGS and LDFLAGS to module build flags.
This makes ASAN buildbot workers to work out-of-the-box.
2020-01-28 19:20:46 +03:00
Max Romanov 1451090d85 Node.js: suppress compilation warning. 2020-01-28 17:06:57 +03:00
Max Romanov 4e0a2002fe Java: fixing configure errors reporting. 2020-01-28 17:03:19 +03:00
Max Romanov 1949be644c Java: introducing SHA512 sum validation for external JARs. 2020-01-28 17:02:51 +03:00
Max Romanov 04bf6457c6 Java: fixing maven repository URL.
It is required to use https scheme and different host to download
packages from maven repository.
2020-01-28 17:01:21 +03:00
Max Romanov a58ca623cd Packages: added curl dependency to fetch Java archives. 2020-01-28 17:00:28 +03:00
Max Romanov 2f8b243fa4 Ruby: changing callback functions prototype for v2.7.
This closes #371 issue on GitHub.
2020-01-28 16:59:12 +03:00
Max Romanov 693a458b4e Go: changing import name for "unit.nginx.org/go".
This patch includes packaging changes - update unit-go installation
directory.
2019-12-25 20:00:32 +03:00
Max Romanov 26ee4cb6c8 Go: introducing SHM_ACK observer.
Each request processed in a separate goroutine.  In case of OOSM state,
during response write, request goroutine blocks on channel which waits
event from main thread about SHM_ACK message from router.
2019-12-24 18:04:21 +03:00
Max Romanov 763bdff401 Node.js: implementing output message drain using SHM_ACK feature.
ServerResponse.write() method tries to write data buffer using libunit
and stores buffers to write in a Server-wide output queue, which is
processed in response to SHM_ACK message from router.

As a side effect 'drain' event implemented and socket.writable flag
reflect current state.
2019-12-24 18:04:17 +03:00
Max Romanov df7caf4650 Introducing port messages to notify about out of shared memory.
- OOSM (out of shared memory).  Sent by application process to router
  when application reaches the limit of allocated shared memory and
  needs more.
- SHM_ACK.  Sent by router to application when the application's shared
  memory is released and the OOSM flag is enabled for the segment.

This implements blocking mode (the library waits for SHM_ACK in case of
out of shared memory condition and retries allocating the required memory
amount) and non-blocking mode (the library notifies the application that
it's out of shared memory and returns control to the application module
that sets up the output queue and puts SHM_ACK in the main message loop).
2019-12-24 18:04:13 +03:00
Max Romanov 64f649f990 Adding "limits/shm" configuration validation and parsing. 2019-12-24 18:04:09 +03:00
Max Romanov 429c5a1c54 Renaming nxt_unit_mmap_buf_remove to nxt_unit_mmap_buf_unlink.
The function unchains the buffer from the buffer's linked list.
2019-12-24 18:04:05 +03:00
Max Romanov 806b3945fe Introducing write tail reference to avoid buffer chain iteration. 2019-12-24 18:04:00 +03:00
Max Romanov faeb73a65e Using non-shared memory buffers for small messages.
Current shared memory buffer implementation uses fixed-size memory blocks,
allocating at least 16384 bytes.  When application sends data in a large
number of small chunks, it makes sense to buffer them or use plain
memory buffers to improve performance and reduce memory footprint.

This patch introduces minimum size limit (1024 bytes) for shared
memory buffers.
2019-12-24 18:03:56 +03:00
Max Romanov f5a2984acf Go: moving source files to the root of the project.
This patch includes packaging changes related to files move.
2019-12-24 17:59:52 +03:00
Max Romanov a427ecd4c5 Go: installing go module for tests into build directory. 2019-12-24 17:59:48 +03:00
Max Romanov 3d712a7078 Packages: making unit-go architecture independent.
To support Go modules, the unit-go module should be platform independent.
All platform-dependent logic is moved to libunit, so the unit-dev package
should be installed before building unit-go.
2019-12-24 17:59:44 +03:00
Max Romanov 823f658c77 Go: linking against libunit. 2019-12-24 17:59:37 +03:00
Max Romanov 55a368e505 Java: fixing racing condition in external JAR download.
Temporary file name with configure process PID used to download
JAR from external repository.  Then file renamed using command 'mv'.

The issue reproduced in clean environment when 2 or more concurrent builds
started.
2019-12-09 18:17:16 +03:00
Max Romanov 4eecf1cb6a Refactoring reference counting of req_app_link.
The reason for the change is that the req_app_link reference count
was incorrect if the application crashed at start; in this case,
the nxt_request_app_link_update_peer() function was never called.

This closes #332 issue on GitHub.
2019-11-26 17:14:53 +03:00
Max Romanov bdd96bc9ed Ruby: fixing initialization sequence.
There was a change (ruby/ruby@6c70fed) in Ruby 2.6 that moved
RUBY_DESCRIPTION global constant definition out of Init_version().
Unit initialized Ruby incorrectly, so the constant was not defined.

This closes #330 issue on GitHub.
2019-11-13 15:53:49 +03:00
Max Romanov f2610d2160 Fixing libunit 'off by 2' issue in library.
Name and value in each header are 0-terminated, so additional 2 bytes
should be allocated for them.  There were several attempts to add these
2 bytes to headers in language modules, but some modules weren't updated.
Also, adding these 2 bytes is specific to the implementation which may be
changed later, so extending this mechanics to modules may cause errors.
2019-11-11 18:04:17 +03:00
Max Romanov 65b03a14a7 Allocating process init struct from runtime memory pool.
This avoids memory leak reports from the address sanitizer.
2019-10-29 15:33:45 +03:00
Max Romanov ad518ae6c4 Python: fixing Python 3.8 build with clang.
Python 3.8 has 'tp_print' field in PyTypeObject struct.  This field is
attributed as deprecated.  So, clang generates warning (which is turned to
error) as a result of initializing this field.  From the other hand, it is
impossible to omit this field in positional initialization.  The solution
is to use designated initializer.

Silencing usage message during configure python.

This is related to #331 issue on GitHub.
2019-10-23 14:04:29 +03:00
Max Romanov 2dbfd7c35e Fixing process crash in case of module load error.
This is related to #330 issue on GitHub.
2019-10-22 16:14:02 +03:00
Max Romanov 8df4468014 Fixing idle connection close function.
There was a typo: nxt_queue_head() used instead of nxt_queue_first() in
connection iteration loop.  This prevents idle connection close on quit.

This closes #334 issue on GitHub.
Thanks to 洪志道 (Hong Zhi Dao).
2019-10-22 16:04:56 +03:00
Max Romanov e54f5f3dc8 Python: fixing build for Python 3.8.
Thanks to tonyafanasyev.
This is related to #331 issue on GitHub.
2019-10-22 16:04:30 +03:00
Max Romanov 9b4e45cafc Fixed "make tests" build without preceding "make".
Currently almost all Unit object files depends on generated nxt_version.h.
This patch adds missing dependence and fixes running make with multiple
jobs.

This closes #318 issue on GitHub.
2019-10-02 19:11:10 +03:00
Max Romanov 2eb6f35ef5 Go: fixing header buffer size calculation.
Header names and values are stored 0-terminated for ease of use in different
languages, so magic number 2 should be added to each name-value pair size.
2019-10-01 19:53:18 +03:00
Max Romanov f2b280aa0c Fixed exiting if a signal arrives during discovery.
When Unit starts, the main process waits for module discovery message for a
while.  If a QUIT signal arrives at this time, the router and controller
processes created by main and Unit stay running.  Also, the main process
doesn't stop them after the second QUIT signal is received in this case.
2019-09-30 16:39:08 +03:00
Max Romanov 6346e641ee Releasing WebSocket frame in case of buffer allocation failure.
Found by Coverity (CID 349456).
2019-09-19 16:28:03 +03:00
Max Romanov 1fac43eebe Fixing master process crash after failed fork.
This closes #312 issue on GitHub.
2019-09-18 22:45:30 +03:00