yahns 0.0.0TP1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/COPYING +674 -0
  4. data/GIT-VERSION-GEN +41 -0
  5. data/GNUmakefile +90 -0
  6. data/README +127 -0
  7. data/Rakefile +60 -0
  8. data/bin/yahns +32 -0
  9. data/examples/README +3 -0
  10. data/examples/init.sh +76 -0
  11. data/examples/logger_mp_safe.rb +28 -0
  12. data/examples/logrotate.conf +32 -0
  13. data/examples/yahns_multi.conf.rb +89 -0
  14. data/examples/yahns_rack_basic.conf.rb +27 -0
  15. data/lib/yahns.rb +73 -0
  16. data/lib/yahns/acceptor.rb +28 -0
  17. data/lib/yahns/client_expire.rb +40 -0
  18. data/lib/yahns/client_expire_portable.rb +39 -0
  19. data/lib/yahns/config.rb +344 -0
  20. data/lib/yahns/daemon.rb +51 -0
  21. data/lib/yahns/fdmap.rb +90 -0
  22. data/lib/yahns/http_client.rb +198 -0
  23. data/lib/yahns/http_context.rb +65 -0
  24. data/lib/yahns/http_response.rb +184 -0
  25. data/lib/yahns/log.rb +73 -0
  26. data/lib/yahns/queue.rb +7 -0
  27. data/lib/yahns/queue_egg.rb +23 -0
  28. data/lib/yahns/queue_epoll.rb +57 -0
  29. data/lib/yahns/rack.rb +80 -0
  30. data/lib/yahns/server.rb +336 -0
  31. data/lib/yahns/server_mp.rb +181 -0
  32. data/lib/yahns/sigevent.rb +7 -0
  33. data/lib/yahns/sigevent_efd.rb +18 -0
  34. data/lib/yahns/sigevent_pipe.rb +29 -0
  35. data/lib/yahns/socket_helper.rb +117 -0
  36. data/lib/yahns/stream_file.rb +34 -0
  37. data/lib/yahns/stream_input.rb +150 -0
  38. data/lib/yahns/tee_input.rb +114 -0
  39. data/lib/yahns/tmpio.rb +27 -0
  40. data/lib/yahns/wbuf.rb +36 -0
  41. data/lib/yahns/wbuf_common.rb +32 -0
  42. data/lib/yahns/worker.rb +58 -0
  43. data/test/covshow.rb +29 -0
  44. data/test/helper.rb +115 -0
  45. data/test/server_helper.rb +65 -0
  46. data/test/test_bin.rb +97 -0
  47. data/test/test_client_expire.rb +132 -0
  48. data/test/test_config.rb +56 -0
  49. data/test/test_fdmap.rb +19 -0
  50. data/test/test_output_buffering.rb +291 -0
  51. data/test/test_queue.rb +59 -0
  52. data/test/test_rack.rb +28 -0
  53. data/test/test_serve_static.rb +42 -0
  54. data/test/test_server.rb +415 -0
  55. data/test/test_stream_file.rb +30 -0
  56. data/test/test_wbuf.rb +136 -0
  57. data/yahns.gemspec +19 -0
  58. metadata +165 -0
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
3
+ # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
4
+ CONSTANT = "Yahns::VERSION"
5
+ RVF = "lib/yahns/version.rb"
6
+ GVF = "GIT-VERSION-FILE"
7
+ DEF_VER = "v0.0.0TP1"
8
+ vn = DEF_VER
9
+
10
+ # First see if there is a version file (included in release tarballs),
11
+ # then try git-describe, then default.
12
+ if File.exist?(".git")
13
+ describe = `git describe --abbrev=4 HEAD 2>/dev/null`.strip
14
+ case describe
15
+ when /\Av[0-9]*/
16
+ vn = describe
17
+ system(*%w(git update-index -q --refresh))
18
+ unless `git diff-index --name-only HEAD --`.chomp.empty?
19
+ vn << "-dirty"
20
+ end
21
+ vn.tr!('-', '.')
22
+ end
23
+ end
24
+
25
+ vn = vn.sub!(/\Av/, "")
26
+ new_ruby_version = "#{CONSTANT} = '#{vn}' # :nodoc:\n"
27
+ cur_ruby_version = File.read(RVF) rescue nil
28
+ if new_ruby_version != cur_ruby_version
29
+ File.open(RVF, "w") { |fp| fp.write(new_ruby_version) }
30
+ end
31
+ File.chmod(0644, RVF)
32
+
33
+ # generate the makefile snippet
34
+ new_make_version = "VERSION = #{vn}\n"
35
+ cur_make_version = File.read(GVF) rescue nil
36
+ if new_make_version != cur_make_version
37
+ File.open(GVF, "w") { |fp| fp.write(new_make_version) }
38
+ end
39
+ File.chmod(0644, GVF)
40
+
41
+ puts vn if $0 == __FILE__
@@ -0,0 +1,90 @@
1
+ # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
2
+ # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
3
+ all::
4
+ pkg = yahns
5
+ RUBY = ruby
6
+ GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
7
+ @./GIT-VERSION-GEN
8
+ -include GIT-VERSION-FILE
9
+ lib := lib
10
+
11
+ all:: test
12
+ test_units := $(wildcard test/test_*.rb)
13
+ test: $(test_units)
14
+ $(test_units):
15
+ $(RUBY) -w -I $(lib) $@ -v
16
+
17
+ test-mt: export N = $(shell nproc 2>/dev/null || echo 4)
18
+ test-mt:
19
+ $(RUBY) -w -I $(lib) $(addprefix -r./,$(test_units)) -eexit --
20
+
21
+ check-warnings:
22
+ @(for i in $$(git ls-files '*.rb'| grep -v '^setup\.rb$$'); \
23
+ do $(RUBY) -d -W2 -c $$i; done) | grep -v '^Syntax OK$$' || :
24
+
25
+ check: test
26
+ coverage: export COVERAGE=1
27
+ coverage:
28
+ > coverage.dump
29
+ $(MAKE) check
30
+ $(RUBY) ./test/covshow.rb
31
+
32
+ coverage-mt: export COVERAGE=1
33
+ coverage-mt:
34
+ > coverage.dump
35
+ $(MAKE) test-mt
36
+ $(RUBY) ./test/covshow.rb
37
+
38
+ pkggem := pkg/$(pkg)-$(VERSION).gem
39
+ pkgtgz := pkg/$(pkg)-$(VERSION).tar.gz
40
+
41
+ fix-perms:
42
+ git ls-tree -r HEAD | awk '/^100644 / {print $$NF}' | xargs chmod 644
43
+ git ls-tree -r HEAD | awk '/^100755 / {print $$NF}' | xargs chmod 755
44
+
45
+ gem: $(pkggem)
46
+
47
+ install-gem: $(pkggem)
48
+ gem install $(CURDIR)/$<
49
+
50
+ $(pkggem): .gem-manifest
51
+ VERSION=$(VERSION) gem build $(pkg).gemspec
52
+ mkdir -p pkg
53
+ mv $(@F) $@
54
+
55
+ pkg_extra := GIT-VERSION-FILE lib/yahns/version.rb NEWS
56
+ NEWS:
57
+ rake -s $@
58
+
59
+ gem-man:
60
+ $(MAKE) -C Documentation/ gem-man
61
+ tgz-man:
62
+ $(MAKE) -C Documentation/ install-man mandir=$(CURDIR)/man
63
+ .PHONY: tgz-man gem-man
64
+
65
+ .gem-manifest: .manifest
66
+ # (ls man/*.?; cat .manifest) | LC_ALL=C sort > $@+
67
+ LC_ALL=C sort < .manifest > $@+
68
+ cmp $@+ $@ || mv $@+ $@; rm -f $@+
69
+ .tgz-manifest: .manifest
70
+ LC_ALL=C sort < .manifest > $@+
71
+ cmp $@+ $@ || mv $@+ $@; rm -f $@+
72
+ .manifest: NEWS fix-perms
73
+ rm -rf man
74
+ (git ls-files; \
75
+ for i in $(pkg_extra); do echo $$i; done) | \
76
+ LC_ALL=C sort > $@+
77
+ cmp $@+ $@ || mv $@+ $@; rm -f $@+
78
+ $(pkgtgz): distdir = pkg/$(pkg)-$(VERSION)
79
+ $(pkgtgz): .tgz-manifest
80
+ @test -n "$(distdir)"
81
+ $(RM) -r $(distdir)
82
+ mkdir -p $(distdir)
83
+ tar cf - $$(cat .tgz-manifest) | (cd $(distdir) && tar xf -)
84
+ cd pkg && tar cf - $(pkg)-$(VERSION) | gzip -9 > $(@F)+
85
+ mv $@+ $@
86
+
87
+ package: $(pkgtgz) $(pkggem)
88
+
89
+ .PHONY: all .FORCE-GIT-VERSION-FILE test $(test_units) NEWS
90
+ .PHONY: check-warnings fix-perms
data/README ADDED
@@ -0,0 +1,127 @@
1
+ yahns - sleepy, multi-threaded, non-blocking application server for Ruby
2
+ ------------------------------------------------------------------------
3
+
4
+ A Free Software, multi-threaded, non-blocking network application server
5
+ designed for low _idle_ power consumption. It is primarily optimized
6
+ for applications with occasional users which see little or no traffic.
7
+ yahns currently hosts Rack/HTTP applications, but may eventually support
8
+ other application types. Unlike some existing servers, yahns is
9
+ extremely sensitive to fatal bugs in the applications it hosts.
10
+
11
+ Features
12
+ --------
13
+
14
+ * _zero_ wakeups when all clients are idle
15
+ * idle client connections may live forever if there is no FD pressure
16
+ * suitable for slow clients, fast clients, or a mixture of both
17
+ * HTTP/0.9 support
18
+ * HTTP/1.1 persistent connections and pipelining
19
+ * decodes HTTP chunked encoding for requests
20
+ * parses HTTP/1.1 trailers in requests
21
+ * supports streaming responses with lazy buffering for slow clients
22
+ * optional streaming input for fast clients
23
+ * able to host multiple applications with different settings
24
+ * uses epoll to scale to many idle connections
25
+ * abuses epoll as a load balancer between threads inside a process
26
+ * optional multi-process support (in addition to threads)
27
+ * fairly balances new clients between multiple processes (on Linux)
28
+
29
+ Supported Platforms
30
+ -------------------
31
+
32
+ yahns is developed primarily for modern GNU/Linux systems.
33
+
34
+ We may support kqueue for FreeBSD/OpenBSD/NetBSD if there is significant
35
+ interest. Non-Free systems/dependencies will never be supported
36
+
37
+ Supported Ruby implementations:
38
+ * (Matz) Ruby 2.0 or later
39
+ * Rubinius 2.0 or later (planned)
40
+
41
+ Contact
42
+ -------
43
+
44
+ We are happy to see feedback of all types via plain-text email.
45
+ Please send comments, user/dev discussion, patches, bug reports,
46
+ and pull requests to Eric Wong at: normalperson@yhbt.net
47
+
48
+ Public mailing list coming soon.
49
+
50
+ This README is our homepage, we would rather be working on HTTP servers
51
+ all day than worrying about the next browser vulnerability because
52
+ HTML/CSS/JS is too complicated for us.
53
+
54
+ * http://yahns.yhbt.net/README
55
+
56
+ Hacking
57
+ -------
58
+
59
+ We use git and follow the same development model as git itself
60
+ (mailing list-oriented, benevolent dictator).
61
+
62
+ git clone git://yahns.yhbt.net/yahns
63
+
64
+ Please use git-format-patch(1) and git-send-email(1) distributed with
65
+ the git(7) suite for generating and sending patches. Please format
66
+ pull requests with the git-request-pull(1) script (also distributed
67
+ with git(7)) and send them via email.
68
+
69
+ See http://www.git-scm.com/ for more information on git.
70
+
71
+ Design
72
+ ------
73
+
74
+ yahns is designed to optimimally use multiple threads with non-blocking I/O.
75
+ The event loop is not a traditional single-threaded design with a mutex
76
+ slapped on as an afterthought, but designed from the beginning to utilize
77
+ multiple threads.
78
+
79
+ * two classes of long-lived, persistent threads
80
+ 1. blocking acceptors
81
+ 2. non-blocking event loop workers
82
+ * epoll acts as a queue (by using one-shot notifications)
83
+ * acceptors accept new clients and put them in the epoll "queue"
84
+ * workers pull clients off the queue, rearming them to epoll on EAGAIN
85
+
86
+ The end result is clients transition freely and fairly between threads
87
+ and will always be able to find the next idle thread to run on.
88
+
89
+ This design works with kqueue, too, and we will support kqueue if there
90
+ is interest. In fact, got our design inspiration from the name "kqueue"
91
+ when working on another project. We may also support libkqueue:
92
+
93
+ http://sourceforge.net/projects/libkqueue/
94
+
95
+ In addition to multiple threads, yahns optionally supports multiple
96
+ processes to work around low FD limits as well as contention in the:
97
+
98
+ * kernel (socket (de)allocation from accept/close)
99
+ * standard C library (malloc/free)
100
+ * Ruby VM (GVL, GC)
101
+ * application it hosts
102
+
103
+ Copyright
104
+ ---------
105
+
106
+ Copyright 2013, Eric Wong <normalperson@yhbt.net> and all contributors.
107
+ License: GPLv3 or later <https://www.gnu.org/licenses/gpl-3.0.txt>
108
+
109
+ yahns is copyrighted Free Software by all contributors, see logs in
110
+ revision control for names and email addresses of all of them. yahns
111
+ contains code from Mongrel, unicorn, and Rainbows! which may also be
112
+ licensed under the GPLv2 or later.
113
+
114
+ yahns is free software; you can redistribute it and/or modify it
115
+ under the terms of the GNU General Public License as published by the
116
+ Free Software Foundation; either version 3 of the License, or (at your
117
+ option) any later version.
118
+
119
+ yahns is distributed in the hope that it will be useful, but WITHOUT ANY
120
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
121
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
122
+ for more details.
123
+
124
+ You should have received a copy of the GNU General Public License along
125
+ with this program; if not, see https://www.gnu.org/licenses/gpl-3.0.txt
126
+
127
+ lrg nabgure ubeevoyl-anzrq freire :>
@@ -0,0 +1,60 @@
1
+ # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
2
+ # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
3
+ require 'tempfile'
4
+ include Rake::DSL
5
+ task "NEWS" do
6
+ latest = nil
7
+ fp = Tempfile.new("NEWS", ".")
8
+ fp.sync = true
9
+ `git tag -l`.split(/\n/).reverse.each do |tag|
10
+ %r{\Av(.+)} =~ tag or next
11
+ version = $1
12
+ header, subject, body = `git cat-file tag #{tag}`.split(/\n\n/, 3)
13
+ header = header.split(/\n/)
14
+ tagger = header.grep(/\Atagger /)[0]
15
+ time = Time.at(tagger.split(/ /)[-2].to_i).utc
16
+ latest ||= time
17
+ date = time.strftime("%Y-%m-%d")
18
+ fp.puts "# #{version} / #{date}\n\n#{subject}"
19
+ if body && body.strip.size > 0
20
+ fp.puts "\n\n#{body}"
21
+ end
22
+ fp.puts
23
+ end
24
+ fp.write("Unreleased\n\n") unless fp.size > 0
25
+ fp.puts "# COPYRIGHT"
26
+ bdfl = 'Eric Wong <normalperson@yhbt.net>'
27
+ fp.puts "Copyright (C) 2013, #{bdfl} and all contributors"
28
+ fp.puts "License: GPLv3 or later (http://www.gnu.org/licenses/gpl-3.0.txt)"
29
+ fp.rewind
30
+ assert_equal fp.read, File.read("NEWS") rescue nil
31
+ fp.chmod 0644
32
+ File.rename(fp.path, "NEWS")
33
+ fp.close!
34
+ end
35
+
36
+ task rsync_docs: "NEWS" do
37
+ dest = ENV["RSYNC_DEST"] || "yahns.yhbt.net:/srv/yahns/"
38
+ top = %w(NEWS README COPYING)
39
+ files = []
40
+
41
+ # git-set-file-times is distributed with rsync,
42
+ # Also available at: http://yhbt.net/git-set-file-times
43
+ # on Debian systems: /usr/share/doc/rsync/scripts/git-set-file-times.gz
44
+ sh("git", "set-file-times", "examples", *top)
45
+
46
+ `git ls-files Documentation/*.txt`.split(/\n/).concat(top).each do |txt|
47
+ gz = "#{txt}.gz"
48
+ tmp = "#{gz}.#$$"
49
+ sh("gzip -9 < #{txt} > #{tmp}")
50
+ st = File.stat(txt)
51
+ File.utime(st.atime, st.mtime, tmp) # make nginx gzip_static happy
52
+ File.rename(tmp, gz)
53
+ files << txt
54
+ files << gz
55
+ end
56
+ sh("rsync --chmod=Fugo=r -av #{files.join(' ')} #{dest}")
57
+
58
+ examples = `git ls-files examples`.split("\n")
59
+ sh("rsync --chmod=Fugo=r -av #{examples.join(' ')} #{dest}/examples/")
60
+ end
@@ -0,0 +1,32 @@
1
+ #!/this/will/be/overwritten/or/wrapped/anyways/do/not/worry/ruby
2
+ # -*- encoding: binary -*-
3
+ # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
4
+ # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
5
+ $stdout.sync = $stderr.sync = true
6
+ require 'yahns'
7
+ require 'optparse'
8
+ config_file = daemonize = nil
9
+ OptionParser.new("", 24, " ") do |opts|
10
+ cmd = File.basename($0)
11
+ opts.banner = "Usage: #{cmd} [options]"
12
+ opts.separator "#{cmd} options:"
13
+ opts.on("-D", "--daemonize", "run daemonized in the background") do |d|
14
+ daemonize = !!d
15
+ end
16
+ opts.on("-c", "--config-file FILE", "yahns config file") do |f|
17
+ config_file = f
18
+ end
19
+ opts.separator "Common options:"
20
+ opts.on_tail("-h", "--help", "Show this message") do
21
+ puts opts.to_s
22
+ exit
23
+ end
24
+ opts.on_tail("-v", "--version", "Show version") do
25
+ puts "#{cmd} v#{Yahns::VERSION}"
26
+ exit
27
+ end
28
+ opts.parse!(ARGV)
29
+ end
30
+ server = Yahns::Server.new(Yahns::Config.new(config_file))
31
+ Yahns::Daemon.daemon(server) if daemonize
32
+ server.start.join
@@ -0,0 +1,3 @@
1
+ All files in this example directory (including this one) are CC0:
2
+ To the extent possible under law, Eric Wong has waived all copyright and
3
+ related or neighboring rights to these examples.
@@ -0,0 +1,76 @@
1
+ #!/bin/sh
2
+ # To the extent possible under law, Eric Wong has waived all copyright and
3
+ # related or neighboring rights to this examples
4
+ set -e
5
+ # Example init script, this can be used with nginx, too,
6
+ # since nginx and yahns accept the same signals
7
+
8
+ # Feel free to change any of the following variables for your app:
9
+ TIMEOUT=${TIMEOUT-60}
10
+ APP_ROOT=/home/x/my_app/current
11
+ PID=$APP_ROOT/tmp/pids/yahns.pid
12
+ CMD="/usr/bin/yahns -D -c $APP_ROOT/config/yahns.rb"
13
+ INIT_CONF=$APP_ROOT/config/init.conf
14
+ action="$1"
15
+ set -u
16
+
17
+ test -f "$INIT_CONF" && . $INIT_CONF
18
+
19
+ old_pid="$PID.oldbin"
20
+
21
+ cd $APP_ROOT || exit 1
22
+
23
+ sig () {
24
+ test -s "$PID" && kill -$1 `cat $PID`
25
+ }
26
+
27
+ oldsig () {
28
+ test -s $old_pid && kill -$1 `cat $old_pid`
29
+ }
30
+
31
+ case $action in
32
+ start)
33
+ sig 0 && echo >&2 "Already running" && exit 0
34
+ $CMD
35
+ ;;
36
+ stop)
37
+ sig QUIT && exit 0
38
+ echo >&2 "Not running"
39
+ ;;
40
+ force-stop)
41
+ sig TERM && exit 0
42
+ echo >&2 "Not running"
43
+ ;;
44
+ restart|reload)
45
+ sig HUP && echo reloaded OK && exit 0
46
+ echo >&2 "Couldn't reload, starting '$CMD' instead"
47
+ $CMD
48
+ ;;
49
+ upgrade)
50
+ if sig USR2 && sleep 2 && sig 0 && oldsig QUIT
51
+ then
52
+ n=$TIMEOUT
53
+ while test -s $old_pid && test $n -ge 0
54
+ do
55
+ printf '.' && sleep 1 && n=$(( $n - 1 ))
56
+ done
57
+ echo
58
+
59
+ if test $n -lt 0 && test -s $old_pid
60
+ then
61
+ echo >&2 "$old_pid still exists after $TIMEOUT seconds"
62
+ exit 1
63
+ fi
64
+ exit 0
65
+ fi
66
+ echo >&2 "Couldn't upgrade, starting '$CMD' instead"
67
+ $CMD
68
+ ;;
69
+ reopen-logs)
70
+ sig USR1
71
+ ;;
72
+ *)
73
+ echo >&2 "Usage: $0 <start|stop|restart|upgrade|force-stop|reopen-logs>"
74
+ exit 1
75
+ ;;
76
+ esac
@@ -0,0 +1,28 @@
1
+ # To the extent possible under law, Eric Wong has waived all copyright and
2
+ # related or neighboring rights to this examples
3
+ #
4
+ # Multi-Processing-safe monkey patch for Logger
5
+ #
6
+ # This monkey patch fixes the case where "preload: true" is used and
7
+ # the application spawns a background thread upon being loaded.
8
+ #
9
+ # This removes all lock from the Logger code and solely relies on the
10
+ # underlying filesystem to handle write(2) system calls atomically when
11
+ # O_APPEND is used. This is safe in the presence of both multiple
12
+ # threads (native or green) and multiple processes when writing to
13
+ # a filesystem with POSIX O_APPEND semantics.
14
+ #
15
+ # It should be noted that the original locking on Logger could _never_ be
16
+ # considered reliable on non-POSIX filesystems with multiple processes,
17
+ # either, so nothing is lost in that case.
18
+
19
+ require 'logger'
20
+ class Logger::LogDevice
21
+ def write(message)
22
+ @dev.syswrite(message)
23
+ end
24
+
25
+ def close
26
+ @dev.close
27
+ end
28
+ end