├── .gitignore ├── CONCEPT.md ├── IMAGE.md ├── README.md ├── api ├── go │ ├── .gitignore │ ├── log │ │ └── log.go │ └── tenki │ │ ├── hash │ │ ├── hash.go │ │ └── hash.py │ │ ├── main.go │ │ └── tenki.go ├── ken │ ├── COPYRIGHT.txt │ ├── Gemfile │ ├── Gemfile.lock │ ├── README.md │ ├── app.rb │ ├── config.ru │ ├── unicorn_config.rb │ ├── unicorn_config_all.rb │ ├── x-ken-all.csv │ ├── x-ken-all.utf8.csv │ └── x-ken-all201509.zip ├── perfect_security │ ├── .gitignore │ ├── client.js │ ├── index.js │ ├── package.json │ ├── server.crt │ └── server.key └── search-name │ ├── .gitignore │ ├── README.md │ ├── build.gradle │ ├── givenname_queries_response.json │ ├── src │ └── main │ │ ├── java │ │ └── net │ │ │ └── isucon │ │ │ ├── KeyValueReader.java │ │ │ ├── Name.java │ │ │ ├── NameIndex.java │ │ │ ├── SearchController.java │ │ │ └── SearchNameApplication.java │ │ └── resources │ │ ├── application.properties │ │ ├── givenname.csv │ │ └── surname.csv │ └── surname_queries_response.json ├── bench ├── .gitignore ├── Gemfile ├── Gemfile.lock ├── agent.rb ├── build.gradle ├── json │ ├── givenname_queries_response.json │ ├── ken_all.json │ └── surname_queries_response.json ├── src │ └── main │ │ └── java │ │ └── net │ │ └── isucon │ │ ├── bench │ │ ├── Checker.java │ │ ├── Config.java │ │ ├── Depender.java │ │ ├── Driver.java │ │ ├── Parameter.java │ │ ├── ResponseType.java │ │ ├── Result.java │ │ ├── Runner.java │ │ ├── Scenario.java │ │ ├── Session.java │ │ ├── State.java │ │ ├── Step.java │ │ └── checker │ │ │ ├── HtmlChecker.java │ │ │ └── JsonChecker.java │ │ └── isucon5f │ │ └── bench │ │ ├── Base.java │ │ ├── Bootstrap.java │ │ ├── Checker.java │ │ ├── Full.java │ │ ├── I5FGivennames.java │ │ ├── I5FJsonData.java │ │ ├── I5FParameter.java │ │ ├── I5FPerfectSecurity.java │ │ ├── I5FSurnames.java │ │ ├── I5FTenki.java │ │ ├── I5FZipcodes.java │ │ ├── Init.java │ │ ├── Load.java │ │ └── ModifyLoader.java └── test.sh ├── data ├── Gemfile ├── Gemfile.lock ├── gen_zipcode_json.rb ├── generate.rb ├── initialize.sql ├── ken_all.json └── source.json ├── eventapp ├── Gemfile ├── Gemfile.lock ├── Procfile ├── app.rb ├── config.ru ├── lib │ └── score.rb ├── public │ ├── css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ └── bootstrap.min.css │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 │ └── js │ │ ├── bootstrap.js │ │ ├── bootstrap.min.js │ │ ├── isucon5portal.js │ │ └── npm.js ├── scripts │ ├── hosts.txt │ ├── init.rb │ └── load_hosts.rb ├── sql │ └── schema.sql ├── unicorn_config.rb ├── update_scores.rb └── views │ ├── index.erb │ ├── layout.erb │ ├── login.erb │ └── team.erb ├── provisioning ├── .gitignore ├── all-in-one │ ├── Gemfile │ ├── ansible │ │ ├── 00_devel.yml │ │ ├── 01_isucon_base.yml │ │ ├── 02_xbuild.yml │ │ ├── 03_middleware.yml │ │ ├── 04_deploy_application.yml │ │ ├── 05_api_servers.yml │ │ ├── 06_deploy_bench_tool.yml │ │ └── _cleanup.yml │ ├── files │ │ ├── bashrc │ │ ├── env.sh │ │ ├── nginx.conf │ │ ├── nginx.php.conf │ │ ├── pg_hba.conf │ │ ├── php.ini │ │ ├── postgresql.conf │ │ ├── schema.sql │ │ ├── sources.list │ │ ├── supervisor.golang.conf │ │ ├── supervisor.java.conf │ │ ├── supervisor.ken.conf │ │ ├── supervisor.node.conf │ │ ├── supervisor.perfect_security.conf │ │ ├── supervisor.perl.conf │ │ ├── supervisor.php.conf │ │ ├── supervisor.python.conf │ │ ├── supervisor.ruby.conf │ │ ├── supervisor.scala.conf │ │ ├── supervisor.search-name.conf │ │ └── supervisor.tenki.conf │ ├── keys │ │ └── root_id_rsa │ └── pack.rb ├── api │ ├── Gemfile │ ├── ansible │ │ ├── 00_devel.yml │ │ ├── 01_isucon_base.yml │ │ ├── 02_xbuild.yml │ │ ├── 03_middleware.yml │ │ ├── 05_api_servers.yml │ │ └── _cleanup.yml │ ├── files │ │ ├── bashrc │ │ ├── env.sh │ │ ├── nginx.conf │ │ ├── php.ini │ │ ├── supervisor.ken.conf │ │ ├── supervisor.perfect_security.conf │ │ ├── supervisor.search-name.conf │ │ └── supervisor.tenki.conf │ ├── keys │ │ ├── deploy_id_rsa │ │ ├── root_id_rsa │ │ └── root_id_rsa.pub │ └── pack.rb ├── bench │ ├── .gitignore │ ├── ansible │ │ ├── 00_devel.yml │ │ ├── 01_isucon_base.yml │ │ ├── 02_xbuild_part.yml │ │ └── 06_deploy_bench_tool.yml │ ├── files │ │ ├── bashrc │ │ ├── env.sh │ │ ├── supervisor.agent1.conf │ │ └── supervisor.agent2.conf │ └── keys │ │ └── deploy_id_rsa ├── eventapp │ ├── ansible │ │ ├── 00_devel.yml │ │ ├── 01_isucon_base.yml │ │ ├── 02_xbuild_part.yml │ │ ├── 03_middleware.yml │ │ └── 07_deploy_event_app.yml │ ├── files │ │ ├── bashrc │ │ ├── env.eventapp.sh │ │ ├── my.cnf │ │ ├── nginx.conf │ │ └── supervisor.eventapp.conf │ └── keys │ │ └── deploy_id_rsa ├── image │ ├── Gemfile │ ├── ansible │ │ ├── 00_devel.yml │ │ ├── 01_isucon_base.yml │ │ ├── 02_xbuild.yml │ │ ├── 03_middleware.yml │ │ ├── 04_deploy_application.yml │ │ └── _cleanup.yml │ ├── files │ │ ├── bashrc │ │ ├── env.sh │ │ ├── nginx.conf │ │ ├── nginx.php.conf │ │ ├── pg_hba.conf │ │ ├── php.ini │ │ ├── postgresql.conf │ │ ├── schema.sql │ │ ├── sources.list │ │ ├── supervisor.golang.conf │ │ ├── supervisor.java.conf │ │ ├── supervisor.node.conf │ │ ├── supervisor.perl.conf │ │ ├── supervisor.php.conf │ │ ├── supervisor.python.conf │ │ ├── supervisor.ruby.conf │ │ └── supervisor.scala.conf │ ├── keys │ │ └── deploy_id_rsa │ └── pack.rb └── inventory.ini ├── regulation.md └── webapp ├── golang ├── .hold ├── README.md ├── app.go └── templates │ ├── login.html │ ├── main.html │ ├── modify.html │ ├── signup.html │ └── user.js ├── java ├── .hold ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── README.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── net │ │ │ └── isucon │ │ │ ├── Isucon5fApplication.java │ │ │ └── RestClientConfig.java │ └── resources │ │ ├── application-sqllog.properties │ │ ├── application.properties │ │ ├── banner.txt │ │ ├── log4jdbc.log4j2.properties │ │ └── templates │ │ ├── login.html │ │ ├── main.html │ │ ├── modify.html │ │ ├── signup.html │ │ └── userjs.html │ └── test │ └── java │ └── net │ └── isucon │ └── Isucon5fApplicationTests.java ├── node ├── .gitignore ├── app.js ├── package.json └── views │ ├── login.ejs │ ├── main.ejs │ ├── modify.ejs │ ├── signup.ejs │ └── userjs.ejs ├── perl ├── .hold ├── README.md ├── app.psgi ├── cpanfile ├── cpanfile.snapshot ├── lib │ ├── Isucon5f.pm │ └── Isucon5f │ │ └── Web.pm ├── t │ └── 00_compile.t └── views │ ├── login.tx │ ├── main.tx │ ├── modify.tx │ ├── signup.tx │ └── userjs.tx ├── php ├── .hold ├── composer.json ├── composer.lock ├── composer.phar ├── index.php ├── nginx.php.conf ├── php-fpm.conf └── templates │ ├── login.php │ ├── main.php │ ├── modify.php │ ├── signup.php │ └── userjs.php ├── python ├── .hold ├── app.py └── views │ ├── login.tpl │ ├── main.tpl │ ├── modify.tpl │ ├── signup.tpl │ └── userjs.tpl ├── ruby ├── Gemfile ├── Gemfile.lock ├── app.rb ├── config.ru ├── unicorn_config.rb └── views │ ├── login.erb │ ├── main.erb │ ├── modify.erb │ ├── signup.erb │ └── userjs.erb ├── scala ├── .hold ├── README.md ├── build.sbt ├── project │ └── plugins.sbt ├── sbt └── src │ └── main │ ├── resources │ └── logback.xml │ ├── scala │ ├── Bootstrap.scala │ └── isucon5 │ │ ├── Isucon5.scala │ │ └── JettyLauncher.scala │ └── webapp │ └── WEB-INF │ ├── scalate │ └── layouts │ │ └── default.ssp │ ├── views │ ├── login.ssp │ ├── main.ssp │ ├── modify.ssp │ ├── signup.ssp │ └── userjs.ssp │ └── web.xml ├── sql ├── .hold ├── initialize.sql ├── initialize_all.sql └── schema.sql └── static ├── .hold ├── css ├── bootstrap-theme.css ├── bootstrap-theme.css.map ├── bootstrap-theme.min.css ├── bootstrap.css ├── bootstrap.css.map ├── bootstrap.min.css ├── jumbotron-narrow.css └── signin.css ├── fonts ├── glyphicons-halflings-regular.eot ├── glyphicons-halflings-regular.svg ├── glyphicons-halflings-regular.ttf ├── glyphicons-halflings-regular.woff └── glyphicons-halflings-regular.woff2 └── js ├── airisu.js ├── bootstrap.js ├── bootstrap.min.js ├── jquery-1.11.3.js └── npm.js /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | #*# 3 | *.swp 4 | .idea 5 | *.iml 6 | target 7 | build 8 | .bundle 9 | vendor 10 | -------------------------------------------------------------------------------- /CONCEPT.md: -------------------------------------------------------------------------------- 1 | # ISUCON5 決勝問題コンセプト 2 | 3 | ## 「間違ったマイクロサービス」 4 | 5 | ``` 6 | 「よっしゃ、これからはマイクロサービスだ!」 7 | 「社長マイクロサービスとは?」 8 | 「細かいサービスをたばねてひとつのサービスとして提供するのだ。幸い我が社では既存の多数のサービスが多数の部署により提供されておる。」 9 | 「は。残念ながらどれもあまりヒットはしておりませんが。」 10 | 「おらんが、これらを束ね、まとめてユーザに提供すれば、こんなに便利なものはないだろう!」 11 | 「は。たしかに。」 12 | 「ということで多数のサービスを束ね、これを提供する。なーに簡単なことだ。」 13 | 「は。簡単でしょうか。」 14 | 「うむ。ということで作っておいた。ついては夕方の発表会をストリーミング中継し、大々的に売り出す」 15 | 「は。突然ですね。」 16 | 「ということでちょっと性能面を見ておいてくれんかね? なーに、キミにとっては他部署のサービスを呼び出すだけだから簡単だろう! ガッハッハ!」 17 | ``` 18 | 19 | 主催者側が予め多種類のWeb APIエンドポイントを用意し、参加者アプリケーションはユーザ(ベンチマーク)からのリクエストに応じてそれらを呼び、結果を統合してレスポンスを返すサービスとする。 20 | 外部APIはもちろん参加者にとってブラックボックスとなっており、参加者は送っているリクエストとレスポンスヘッダ、レスポンスボディの内容を精査する必要があるだろう。 21 | 22 | ## 技術的ポイント 23 | 24 | HTTP APIエンドポイント関連のアイデアとしては以下のようなものがある 25 | 26 | * 参照実装では最初は多数の呼び出し先に対して直列に(1-by-1で)呼び出すように書く (多数のAPIエンドポイントへの並列リクエストに書き換えられるかがキモ) 27 | * Last-Modified, If-Modified-Since, Cache-Control, ETag などキャッシュ制御に関するHTTP仕様をフルに扱うAPIが存在する 28 | * いっぽうそういったものを全く解釈しないものもある (が、コンテンツの中身から明らかに呼び出し元でキャッシュできるものがある) 29 | * レスポンスまで必ず 0.5 秒待たせるなど、妙に遅いエンドポイントなどを含む 30 | * あるエンポイントは呼び出しユーザ毎に1コネクションしか許さない(並列リクエストを許さない)が、そのエンドポイントに2リクエスト以上送る必要がある 31 | * **そしてそのエンドポイントはHTTP/2対応している**のでHTTP/2並列リクエストが使える (プロトコルをhttpsのみ対応にしてヒントとする) 32 | * HTTP APIエンドポイントを複数種類の言語で実装することでレスポンスヘッダや速度特性にバリエーションを出す 33 | 34 | その他の技術的アイデアとしては以下のようなものがある 35 | 36 | * PostgreSQLを使う(適度にボトルネックも作りたい) 37 | * HTMLを返すリクエストハンドラとJSONを返すリクエストハンドラが存在する 38 | * ユーザごとに(?) .js をテンプレートから生成して返す部分が存在するようにする(が、実はパターン数が決まっており静的生成できるようにする) 39 | * 当然だがログイン機能とセッションの扱いが必要 40 | 41 | ベンチマークについても以下のような点に配慮が必要 42 | 43 | * ベンチマーカーはHTTP/1.1 44 | * 1リクエスト-レスポンスが極めて遅いが高速化していったときにはかなり高スループットになる 45 | * 並列度をかなり上げたベンチマーカーが必要 46 | * Redirect先の変更時にLocationを追ってコンテンツ取得するケースも存在する 47 | * JavaScriptファイルが壊れていないかどうか確認する方法が必要、一致チェックでいい? 48 | 49 | ## 今回の出題者にとってのポイント 50 | 51 | * サーバサイドとして HTTP/2 を扱う (HTTP API エンドポイント) 52 | * クライアントサイドに HTTP/2 を扱えるものは何があるかを知っておく(実装の必要はない) 53 | * それなりに高性能なHTTP API エンドポイントを作ってホストする (h2o+mruby? nginx+lua? go? そのほかLL? 色々ありそう) 54 | * PostgreSQL 55 | 56 | ## HTTP API アイデア (under construction) 57 | 58 | ### 2015年の日本の祝日情報API 59 | 60 | プロトコル的に何も対応してない(しかも遅い)が日本の祝日なんて変わらないからキャッシュできるに決まってるだろJK 61 | 62 | ### 郵便番号→住所API 63 | 64 | ユーザを超えて一度クエリされたものはキャッシュ可能: ただし本番計測ではフレッシュな(作業時間中は一度もクエリされなかった)データセットを使う 65 | 66 | KEN_ALL.csv をきちんとparseできるライブラリが存在する言語で書くこと 67 | 68 | ### ユーザの予定リストを返すAPI 69 | 70 | ただしある日についての1リクエストで1予定(と、他にまだ予定があるかどうか)しか返ってこないので直列リクエストが必要 71 | 「ユーザ x 日付」 の組合せがキーになるが、これも本番計測ではフレッシュなデータセットを使うこと 72 | 73 | これはもうちょっと工夫できる余地があったほうがいいかな? ベンチ1リクエストに対して複数の日付に関するAPI callが必要でそこは並列化できるとか? 74 | 75 | ### ユーザの謎のデータに対して謎のデータを返すAPI 76 | 77 | イメージとしてはキーを与えると暗号化済みのデータを返してくれる、という感じ(適当なアルゴリズムで生成する, `key -> { sha512(key.char(0) + key.char(-1) + key) }` みたいな?) 78 | HTTP/2 で並列に処理させられるサービスとしてはこのあたりが適当? 79 | こいつももちろん遅い 80 | 81 | ### (ほか何かアイデア募集中) 82 | 83 | 4種類あれば十分? もうあとふたつみっつ欲しい気がする 84 | -------------------------------------------------------------------------------- /api/go/.gitignore: -------------------------------------------------------------------------------- 1 | tenki/tenki 2 | -------------------------------------------------------------------------------- /api/go/log/log.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import ( 4 | "io" 5 | "log" 6 | "os" 7 | "sync" 8 | "sync/atomic" 9 | ) 10 | 11 | var ( 12 | mutex sync.RWMutex 13 | logger *log.Logger = nil 14 | verbosity int32 = 0 15 | ) 16 | 17 | func init() { 18 | setLogger(os.Stdout) 19 | } 20 | 21 | func setLogger(out io.Writer) { 22 | mutex.Lock() 23 | logger = log.New(out, "", 0) 24 | mutex.Unlock() 25 | } 26 | 27 | func getLogger() *log.Logger { 28 | mutex.RLock() 29 | lgr := logger 30 | mutex.RUnlock() 31 | return lgr 32 | } 33 | 34 | func SetOutput(out io.Writer) { 35 | setLogger(out) 36 | } 37 | 38 | func SetLevel(level int) { 39 | atomic.StoreInt32(&verbosity, int32(level)) 40 | } 41 | 42 | func V(level int) bool { 43 | return int32(level) <= atomic.LoadInt32(&verbosity) 44 | } 45 | 46 | func Print(v ...interface{}) { 47 | lgr := getLogger() 48 | if lgr != nil { 49 | lgr.Print(v) 50 | } 51 | } 52 | 53 | func Println(v ...interface{}) { 54 | lgr := getLogger() 55 | if lgr != nil { 56 | lgr.Println(v) 57 | } 58 | } 59 | 60 | func Printf(format string, v ...interface{}) { 61 | lgr := getLogger() 62 | if lgr != nil { 63 | lgr.Printf(format, v...) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /api/go/tenki/hash/hash.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/md5" 5 | "encoding/binary" 6 | "flag" 7 | "fmt" 8 | ) 9 | 10 | func toInt(date, secret string) int { 11 | str := fmt.Sprintf("%s %s", date, secret) 12 | sum := md5.Sum([]byte(str)) 13 | num := binary.BigEndian.Uint32(sum[:4]) 14 | return int(num) 15 | } 16 | 17 | func main() { 18 | var date string 19 | var secret string 20 | flag.StringVar(&date, "d", "", "date string") 21 | flag.StringVar(&secret, "s", "happyhalloween", "secret") 22 | flag.Parse() 23 | 24 | // Tue, 27 Oct 2015 08:46:40 JST ==> 51498849 25 | // Tue, 27 Oct 2015 08:46:41 JST ==> 1366538060 26 | // Tue, 27 Oct 2015 08:46:42 JST ==> 1443194715 27 | n := toInt(date, secret) 28 | fmt.Println(n) 29 | } 30 | -------------------------------------------------------------------------------- /api/go/tenki/hash/hash.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | $ python3 hash.py --date="Tue, 27 Oct 2015 08:46:40 JST" 5 | 51498849 6 | """ 7 | 8 | import argparse 9 | import hashlib 10 | import struct 11 | 12 | def toint(date, secret): 13 | s = date + " " + secret 14 | m = hashlib.md5(s.encode("utf-8")) 15 | d = m.digest() 16 | n = struct.unpack(">I", d[0:4])[0] 17 | return n 18 | 19 | parser = argparse.ArgumentParser() 20 | parser.add_argument('--date', type=str) 21 | parser.add_argument('--secret', type=str, default="happyhalloween") 22 | args = parser.parse_args() 23 | 24 | n = toint(args.date, args.secret) 25 | print("%s ==> %d" % (args.date, n)) 26 | -------------------------------------------------------------------------------- /api/ken/COPYRIGHT.txt: -------------------------------------------------------------------------------- 1 | x-ken-all.csv: http://zipcloud.ibsnet.co.jp/ 2 | -------------------------------------------------------------------------------- /api/ken/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem 'sinatra' 4 | gem 'sinatra-contrib' 5 | gem 'unicorn' 6 | -------------------------------------------------------------------------------- /api/ken/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | backports (3.6.6) 5 | kgio (2.10.0) 6 | multi_json (1.11.2) 7 | rack (1.6.4) 8 | rack-protection (1.5.3) 9 | rack 10 | rack-test (0.6.3) 11 | rack (>= 1.0) 12 | raindrops (0.15.0) 13 | sinatra (1.4.6) 14 | rack (~> 1.4) 15 | rack-protection (~> 1.4) 16 | tilt (>= 1.3, < 3) 17 | sinatra-contrib (1.4.6) 18 | backports (>= 2.0) 19 | multi_json 20 | rack-protection 21 | rack-test 22 | sinatra (~> 1.4.0) 23 | tilt (>= 1.3, < 3) 24 | tilt (2.0.1) 25 | unicorn (4.9.0) 26 | kgio (~> 2.6) 27 | rack 28 | raindrops (~> 0.7) 29 | 30 | PLATFORMS 31 | ruby 32 | 33 | DEPENDENCIES 34 | sinatra 35 | sinatra-contrib 36 | unicorn 37 | -------------------------------------------------------------------------------- /api/ken/README.md: -------------------------------------------------------------------------------- 1 | # KEN_ALL API 2 | 3 | ```sh 4 | bundle exec unicorn -c unicorn_config.rb 5 | ``` 6 | 7 | **Performance: 820.99 [#/sec]** 8 | 9 | ``` 10 | $ ab -c4 -t10 http://127.0.0.1:8080/9220011 11 | This is ApacheBench, Version 2.3 <$Revision: 1663405 $> 12 | Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ 13 | Licensed to The Apache Software Foundation, http://www.apache.org/ 14 | 15 | Benchmarking 127.0.0.1 (be patient) 16 | Completed 5000 requests 17 | Completed 10000 requests 18 | Finished 13870 requests 19 | 20 | 21 | Server Software: 22 | Server Hostname: 127.0.0.1 23 | Server Port: 8080 24 | 25 | Document Path: /9220011 26 | Document Length: 176 bytes 27 | 28 | Concurrency Level: 4 29 | Time taken for tests: 16.894 seconds 30 | Complete requests: 13870 31 | Failed requests: 0 32 | Total transferred: 4896110 bytes 33 | HTML transferred: 2441120 bytes 34 | Requests per second: 820.99 [#/sec] (mean) 35 | Time per request: 4.872 [ms] (mean) 36 | Time per request: 1.218 [ms] (mean, across all concurrent requests) 37 | Transfer rate: 283.02 [Kbytes/sec] received 38 | 39 | Connection Times (ms) 40 | min mean[+/-sd] median max 41 | Connect: 0 1 45.8 0 2701 42 | Processing: 1 2 1.0 2 66 43 | Waiting: 1 2 0.8 1 56 44 | Total: 1 3 45.9 2 2704 45 | WARNING: The median and mean for the waiting time are not within a normal deviation 46 | These results are probably not that reliable. 47 | 48 | Percentage of the requests served within a certain time (ms) 49 | 50% 2 50 | 66% 2 51 | 75% 2 52 | 80% 2 53 | 90% 2 54 | 95% 3 55 | 98% 3 56 | 99% 4 57 | 100% 2704 (longest request) 58 | ``` 59 | -------------------------------------------------------------------------------- /api/ken/app.rb: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | require 'csv' 3 | 4 | csvfile = File.expand_path("../x-ken-all.utf8.csv", __FILE__) 5 | 6 | data = {} # num => [ data1, data2, ... ] 7 | # data is [ "北海道 札幌市 中央区旭ケ丘" ] 8 | 9 | # 13110,"153 ","1530042","トウキョウト","メグロク","アオバダイ","東京都","目黒区","青葉台",0,0,1,0,0,0 10 | CSV.foreach(csvfile, "r:utf-8") do |row| 11 | zipcode = row[2] 12 | address = "#{row[6]} #{row[7]} #{row[8]}" 13 | data[zipcode] ||= [] 14 | data[zipcode] << address 15 | end 16 | 17 | require 'sinatra' 18 | require 'sinatra/contrib' 19 | 20 | get '/' do 21 | addrs = data[params['zipcode']] 22 | sleep(0.1) 23 | if addrs 24 | json({zipcode: params['zipcode'], addresses: addrs}) 25 | else 26 | json({zipcode: params['zipcode'], addresses: []}) 27 | end 28 | end 29 | 30 | get '/:zipcode' do 31 | addrs = data[params['zipcode']] 32 | sleep(0.1) 33 | if addrs 34 | json({zipcode: params['zipcode'], addresses: addrs}) 35 | else 36 | json({zipcode: params['zipcode'], addresses: []}) 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /api/ken/config.ru: -------------------------------------------------------------------------------- 1 | require_relative './app' 2 | 3 | run Sinatra::Application 4 | -------------------------------------------------------------------------------- /api/ken/unicorn_config.rb: -------------------------------------------------------------------------------- 1 | worker_processes 64 2 | preload_app true 3 | listen 8080 4 | # pid "/home/isucon/apikh/ken/unicorn.pid" 5 | -------------------------------------------------------------------------------- /api/ken/unicorn_config_all.rb: -------------------------------------------------------------------------------- 1 | worker_processes 8 2 | preload_app true 3 | listen 8082 4 | # pid "/home/isucon/apikh/ken/unicorn.pid" 5 | -------------------------------------------------------------------------------- /api/ken/x-ken-all.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isucon/isucon5-final/981f7721e94e655280d71f70f64fa13b94181128/api/ken/x-ken-all.csv -------------------------------------------------------------------------------- /api/ken/x-ken-all201509.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isucon/isucon5-final/981f7721e94e655280d71f70f64fa13b94181128/api/ken/x-ken-all201509.zip -------------------------------------------------------------------------------- /api/perfect_security/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /api/perfect_security/client.js: -------------------------------------------------------------------------------- 1 | var opt = { 2 | host: 'localhost', 3 | port: 8082, 4 | path: '/tokens', 5 | headers: { 'x-perfect-security-token': 'xxxxxxxxxxx' }, 6 | cert: require('fs').readFileSync('./server.crt'), 7 | rejectUnauthorized: false 8 | }; 9 | var req = require('http2').request(opt, function(res) { 10 | console.log('code:' + res.statusCode); 11 | res.on('data', function(chunk){ console.log(chunk.toString()); }); 12 | res.on('end', function(){ 13 | console.log('end.'); 14 | }); 15 | }); 16 | 17 | -------------------------------------------------------------------------------- /api/perfect_security/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "perfect_security", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "dependencies": { 7 | "http2": "^3.2.0" 8 | }, 9 | "devDependencies": {}, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "", 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /api/perfect_security/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDIjCCAgoCCQCPDKaqyBvUWzANBgkqhkiG9w0BAQUFADBTMQswCQYDVQQGEwJK 3 | UDEOMAwGA1UECBMFS3lvdG8xDjAMBgNVBAcTBUt5b3RvMRAwDgYDVQQKEwdFeGFt 4 | cGxlMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMTUxMDI1MTEzNzUxWhcNMTgwODE0 5 | MTEzNzUxWjBTMQswCQYDVQQGEwJKUDEOMAwGA1UECBMFS3lvdG8xDjAMBgNVBAcT 6 | BUt5b3RvMRAwDgYDVQQKEwdFeGFtcGxlMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEi 7 | MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2ioox9f6auqsT/N4U1hYUvKZl 8 | IFsWhcZzMEKrNXDaZnW4PY66hQpH2vzK16DDgWujvJdyt/VZDRYzqaivl3KB8mSQ 9 | 3hZlVZY8rF28s30/U9mX0X07R4CKk3pORxRhxpQrR7ScgVv46Aa+O4Hs8JkhKob/ 10 | mB8mffueRanmGZ9bppHYvvte5oW5pRLqDxLzSkMQE5NsHd2bwwHjE9i4ofvTQfzf 11 | soSS5qB8znTLzsoC11IuxmQzBJRIBBhhHexIZnQ53eNQdSdjw2bis+p7gN5XwyeU 12 | M7f2OJ0qTyVc5iRqj61gLUqmZDFbgvWkc0D33JtrMw4AIICBFXEuXFXkoIetAgMB 13 | AAEwDQYJKoZIhvcNAQEFBQADggEBAHp1C8WtaCM+X74smbqL4aS4dJx/Yyjb9ugs 14 | gyr77/VeaRSlM/ju0wqStY/mRvx4WZoDAG81xHv8wrs/Ojb3xpfUT7JRpVrRGya5 15 | ZX39KDHo4Q2AGdPSNTIW/VjLMyM7QRrNKK1WYyphYj2KgpyNSWUpiPGR5H082YVL 16 | 7VOj+C5NtfToExQkMyzvXM519rpn/U5yz4x8nRAXm3KFrJ135J72UmaKhtFocgeJ 17 | 3G5pVsud+sfmhhVYGiizR3jBMz4QXMfCZvpNmRDQ8UPJdcEoG7vBQcVixFbbb/Vg 18 | QcqdUAi1Dc2phtepfgmuek+J9Wgsq1nBcJqHv9bS6HRK0aj/e1o= 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /api/perfect_security/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEAtoqKMfX+mrqrE/zeFNYWFLymZSBbFoXGczBCqzVw2mZ1uD2O 3 | uoUKR9r8ytegw4Fro7yXcrf1WQ0WM6mor5dygfJkkN4WZVWWPKxdvLN9P1PZl9F9 4 | O0eAipN6TkcUYcaUK0e0nIFb+OgGvjuB7PCZISqG/5gfJn37nkWp5hmfW6aR2L77 5 | XuaFuaUS6g8S80pDEBOTbB3dm8MB4xPYuKH700H837KEkuagfM50y87KAtdSLsZk 6 | MwSUSAQYYR3sSGZ0Od3jUHUnY8Nm4rPqe4DeV8MnlDO39jidKk8lXOYkao+tYC1K 7 | pmQxW4L1pHNA99ybazMOACCAgRVxLlxV5KCHrQIDAQABAoIBAQCGqKjNtmS+DBqM 8 | QiwqPsxHO+ucCkRn1wPQkbd8yY2Y76DD61VRLzeoTlnR4UPNNboMLeGjVSV/LfJE 9 | 5lF0R0rHpeKeI9dtpbeQxq7Xt6kbgGWyY234vwSKNcUx3amhf3ZqfxkzoxIQCkp/ 10 | JzLvcYXlO5QfFT9Vi/aEiWuOPTSbzIQgZTEoWt1unfSIRp5+argTWG7HirLOna5x 11 | 92oaHn6G30hMk0tNMIFNTEN6F/l7CjIbWGibmoaY0+PdKfsMxKeTKbZAe/wyrtfa 12 | visu0oLxUWjHszJ9Omd8LErNQrODK5JN7+PKB34densYHkkloTBQhi0TzIPdWHLw 13 | hcIeTIUBAoGBAN0u8uUvGNOzNC5GYKq23k0aYHDmVAcU61i4vt4SoxON2P+P1ppx 14 | JBxcao1+U3GunIGMTMo/wN7eZkXioqGnq9dfkBOV4l7WeZRTLZLko95NiavP2X5H 15 | M2jnWdBareFGO4EhCBdGW88ZrOwdF6cPHLwdq4V7/2qDGlylL5rhzGRhAoGBANNG 16 | a9KtAJKNrsbj0h/QWgHv5L/4Gmr/BNVhwHss1CEqbU3c3F7giPc2cQ13423VJcQT 17 | tD2B2L7J1m85sApyTXIfKoGieqevw9SxBZiOQ/tUAWg7iT7RVr7zDjQeEzEpA7tC 18 | 1GiU1E92/FxPZtzUdOdU8124gtuLefuMUP0H5ebNAoGAY3rOPE4meHDNM1Lr/1wo 19 | N715Ss4NVPIPt+O/1NnFBvJxeuASwXvJpgfa1LDQjvzd31Ze40gxUwvsK9p3EwX6 20 | v+93OZfcLJOCMzgF819qZH2zQddGFwmnEbOcLZ3bPsr70GQu42j9ufPuVnPvQ3AE 21 | mIcvseXHRvyYSrrw4lRUPYECgYEAzQitgQIV6SQItsnHVMqNXw3hcA+mC6o7lZ1M 22 | //zMTPdwpjytvIGpSkiSRGDR3Pgas4PvyjUmFFmqebyBRFITKKpoRPBamjuwD8xP 23 | wvJltRWcW/xTQBxGU/9rDFcXhwDntyavHmM4+3lchXUlPTAN16aQm6aBj/B2zBEr 24 | U7QDgA0CgYA3v+OEp5hDvwXvSIJW0Y+9ZAjxADhQwKtcdcs6fCk1n8REv7nRweHu 25 | LB3L9efwtiILDO+m22woeqtbyRQvInVP4zr2OtRIVt0yqWyWFa7PpRzIcztf3rZD 26 | oaxW7As3zMow2rNHJvCK/FVikfCUnYTfdFe3Tl88KEbuNYAbOaDK2g== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /api/search-name/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | .idea 4 | *.iml 5 | gradle/wrapper 6 | gradlew 7 | gradlew.bat 8 | -------------------------------------------------------------------------------- /api/search-name/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | springBootVersion = '1.2.6.RELEASE' 4 | } 5 | repositories { 6 | // NOTE: You should declare only repositories that you need here 7 | mavenLocal() 8 | mavenCentral() 9 | maven { url "http://repo.spring.io/release" } 10 | maven { url "http://repo.spring.io/milestone" } 11 | maven { url "http://repo.spring.io/snapshot" } 12 | } 13 | dependencies { 14 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 15 | } 16 | } 17 | 18 | apply plugin: 'java' 19 | apply plugin: 'eclipse' 20 | apply plugin: 'idea' 21 | apply plugin: 'spring-boot' 22 | 23 | jar { 24 | baseName = 'isucon5-search-name' 25 | version = '0.0.0' 26 | } 27 | 28 | run { 29 | systemProperties = System.properties 30 | } 31 | 32 | repositories { 33 | // NOTE: You should declare only repositories that you need here 34 | mavenLocal() 35 | mavenCentral() 36 | maven { url "http://repo.spring.io/release" } 37 | maven { url "http://repo.spring.io/milestone" } 38 | maven { url "http://repo.spring.io/snapshot" } 39 | } 40 | 41 | dependencies { 42 | compile("org.springframework.boot:spring-boot-starter-web") 43 | compile("org.springframework.boot:spring-boot-starter-actuator") 44 | testCompile("org.springframework.boot:spring-boot-starter-test") 45 | } 46 | 47 | task wrapper(type: Wrapper) { 48 | gradleVersion = '2.7' 49 | } 50 | -------------------------------------------------------------------------------- /api/search-name/src/main/java/net/isucon/KeyValueReader.java: -------------------------------------------------------------------------------- 1 | package net.isucon; 2 | 3 | import java.io.*; 4 | 5 | class KeyValueReader { 6 | private final BufferedReader br; 7 | private KeyValue ptr; 8 | 9 | public KeyValueReader(InputStream is) throws UnsupportedEncodingException { 10 | br = new BufferedReader(new InputStreamReader(is, "UTF-8")); 11 | } 12 | 13 | public boolean next() throws IOException { 14 | final String l = br.readLine(); 15 | if (l == null) { 16 | return false; 17 | } 18 | final String[] kv = l.split(","); 19 | if (kv.length != 2) { 20 | throw new IllegalStateException("Invalid input. [" + l + "] must contain at least and only one ','."); 21 | } 22 | this.ptr = new KeyValue(kv[0], kv[1]); 23 | return true; 24 | } 25 | 26 | public KeyValue get() { 27 | return this.ptr; 28 | } 29 | 30 | public static final class KeyValue { 31 | private final String key; 32 | private final String value; 33 | 34 | public KeyValue(String key, String value) { 35 | this.key = key; 36 | this.value = value; 37 | } 38 | 39 | public String key() { 40 | return key; 41 | } 42 | 43 | public String value() { 44 | return value; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /api/search-name/src/main/java/net/isucon/Name.java: -------------------------------------------------------------------------------- 1 | package net.isucon; 2 | 3 | class Name { 4 | private final String yomi; 5 | private final String name; 6 | 7 | public Name(String yomi, String name) { 8 | this.yomi = yomi; 9 | this.name = name; 10 | } 11 | 12 | public String getYomi() { 13 | return yomi; 14 | } 15 | 16 | public String getName() { 17 | return name; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /api/search-name/src/main/java/net/isucon/NameIndex.java: -------------------------------------------------------------------------------- 1 | package net.isucon; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.text.Normalizer; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | class NameIndex { 10 | private final NormalizedName[] names; 11 | 12 | public NameIndex(String resource) throws IOException { 13 | final List list = new ArrayList<>(); 14 | try (InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream(resource)) { 15 | final KeyValueReader kvr = new KeyValueReader(is); 16 | while (kvr.next()) { 17 | final String yomi = kvr.get().key(); 18 | final String name = kvr.get().value(); 19 | list.add(new NormalizedName(normKana(yomi), name, Normalizer.normalize(name, Normalizer.Form.NFKC))); 20 | } 21 | names = list.toArray(new NormalizedName[list.size()]); 22 | } 23 | } 24 | 25 | public Name[] searchName(String query, int maxNum) { 26 | final String q = normKana(query); 27 | final List ret = new ArrayList<>(); 28 | int i = 0; 29 | for (NormalizedName n : names) { 30 | if (n.yomi.startsWith(q) || n.normName.startsWith(q)) { 31 | ret.add(new Name(n.yomi, n.name)); 32 | i++; 33 | if (i >= maxNum) { 34 | break; 35 | } 36 | } 37 | } 38 | return ret.toArray(new Name[ret.size()]); 39 | } 40 | 41 | private static String normKana(String str) { 42 | final StringBuffer sb = new StringBuffer(Normalizer.normalize(str, Normalizer.Form.NFKC)); 43 | for (int i = 0; i < sb.length(); i++) { 44 | char c = sb.charAt(i); 45 | if (c >= 'ぁ' && c <= 'ん') { 46 | sb.setCharAt(i, (char)(c - 'ぁ' + 'ァ')); 47 | } 48 | } 49 | return sb.toString(); 50 | } 51 | 52 | private static final class NormalizedName { 53 | private final String yomi; 54 | private final String name; 55 | private final String normName; 56 | 57 | public NormalizedName(String yomi, String name, String normName) { 58 | this.yomi = yomi; 59 | this.name = name; 60 | this.normName = normName; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /api/search-name/src/main/java/net/isucon/SearchController.java: -------------------------------------------------------------------------------- 1 | package net.isucon; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RequestMethod; 6 | import org.springframework.web.bind.annotation.RequestParam; 7 | import org.springframework.web.bind.annotation.ResponseBody; 8 | 9 | import java.io.IOException; 10 | 11 | @Controller 12 | @SuppressWarnings("unused") 13 | public class SearchController { 14 | private final NameIndex surnameIndex; 15 | private final NameIndex givennameIndex; 16 | private static final int MAX_NUM = 30; 17 | 18 | public SearchController() throws IOException { 19 | surnameIndex = new NameIndex("surname.csv"); 20 | givennameIndex = new NameIndex("givenname.csv"); 21 | } 22 | 23 | @RequestMapping(value = "/surname", method = RequestMethod.GET) 24 | public 25 | @ResponseBody 26 | Result searchSurname(@RequestParam(value = "q", required = true) String query) { 27 | try { Thread.sleep(100); } catch (InterruptedException e) {} 28 | return new Result(query, surnameIndex.searchName(query, MAX_NUM)); 29 | } 30 | 31 | @RequestMapping(value = "/givenname", method = RequestMethod.GET) 32 | public 33 | @ResponseBody 34 | Result searchGivenName(@RequestParam(value = "q", required = true) String query) { 35 | try { Thread.sleep(100); } catch (InterruptedException e) {} 36 | return new Result(query, givennameIndex.searchName(query, MAX_NUM)); 37 | } 38 | 39 | private static final class Result { 40 | private final String query; 41 | private final Name[] result; 42 | 43 | public Result(String query, Name[] result) { 44 | this.query = query; 45 | this.result = result; 46 | } 47 | 48 | public String getQuery() { 49 | return query; 50 | } 51 | 52 | public Name[] getResult() { 53 | return result; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /api/search-name/src/main/java/net/isucon/SearchNameApplication.java: -------------------------------------------------------------------------------- 1 | package net.isucon; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class SearchNameApplication { 8 | public static void main(String[] args) throws Exception { 9 | SpringApplication.run(SearchNameApplication.class, args); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /api/search-name/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port = 8081 2 | -------------------------------------------------------------------------------- /bench/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .gradle/ 3 | -------------------------------------------------------------------------------- /bench/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem "mysql2-cs-bind" 4 | -------------------------------------------------------------------------------- /bench/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | mysql2 (0.4.1) 5 | mysql2-cs-bind (0.0.6) 6 | mysql2 7 | 8 | PLATFORMS 9 | ruby 10 | 11 | DEPENDENCIES 12 | mysql2-cs-bind 13 | 14 | BUNDLED WITH 15 | 1.10.6 16 | -------------------------------------------------------------------------------- /bench/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "java" 2 | apply plugin: "application" 3 | 4 | repositories { 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | compile "commons-cli:commons-cli:1.3.1" 10 | compile "org.eclipse.jetty:jetty-client:9.3.3.v20150827" 11 | compile "org.apache.httpcomponents:httpclient:4.5.1" 12 | compile "org.jsoup:jsoup:1.8.3" 13 | compile "com.fasterxml.jackson.core:jackson-databind:2.6.3" 14 | compile "com.jayway.jsonpath:json-path:2.0.0" 15 | compile "org.slf4j:slf4j-nop:1.7.12" 16 | } 17 | 18 | compileJava { 19 | gradle.projectsEvaluated { 20 | if (project.hasProperty('warn')) { 21 | options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" 22 | } 23 | } 24 | options.encoding = 'UTF-8' 25 | } 26 | 27 | mainClassName = 'net.isucon.bench.Runner' 28 | 29 | run { 30 | // pass stdin to application 31 | standardInput = System.in 32 | 33 | // gradle run -Pargs="v1 v2" 34 | if (project.hasProperty('args')) { 35 | // set splitted "args" property values into 'args' option of run task 36 | args project.args.split('\\s+') 37 | } else { 38 | // default check target 39 | // gradle run -Pargs="net.isucon.isucon5f.bench.Bootstrap 127.0.0.1" 40 | args "net.isucon.isucon5f.bench.Full 127.0.0.1".split('\\s+') 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /bench/json/givenname_queries_response.json: -------------------------------------------------------------------------------- 1 | ../../api/search-name/givenname_queries_response.json -------------------------------------------------------------------------------- /bench/json/ken_all.json: -------------------------------------------------------------------------------- 1 | ../../data/ken_all.json -------------------------------------------------------------------------------- /bench/json/surname_queries_response.json: -------------------------------------------------------------------------------- 1 | ../../api/search-name/surname_queries_response.json -------------------------------------------------------------------------------- /bench/src/main/java/net/isucon/bench/Config.java: -------------------------------------------------------------------------------- 1 | package net.isucon.bench; 2 | 3 | public class Config { 4 | // TODO: variable GET/POST timeouts per requests 5 | public static final long GET_TIMEOUT = 30 * 1000; 6 | public static final long POST_TIMEOUT = 30 * 1000; 7 | 8 | public static final String DEFAULT_USER_AGENT = "Isucon bench"; 9 | 10 | public String scheme; 11 | public String host; 12 | public int port; 13 | public String agent; 14 | 15 | public Config() { 16 | this.scheme = "http"; 17 | this.host = null; 18 | this.port = 0; 19 | this.agent = DEFAULT_USER_AGENT; 20 | } 21 | 22 | public String uri(String path) { 23 | if (port == 0) { 24 | return uriDefaultPort(path); 25 | } else { 26 | return String.format("%s://%s:%d%s", scheme, host, port, path); 27 | } 28 | } 29 | 30 | public String uriDefaultPort(String path) { 31 | return String.format("%s://%s%s", scheme, host, path); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /bench/src/main/java/net/isucon/bench/Depender.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isucon/isucon5-final/981f7721e94e655280d71f70f64fa13b94181128/bench/src/main/java/net/isucon/bench/Depender.java -------------------------------------------------------------------------------- /bench/src/main/java/net/isucon/bench/ResponseType.java: -------------------------------------------------------------------------------- 1 | package net.isucon.bench; 2 | 3 | enum ResponseType { 4 | SUCCESS, 5 | REDIRECT, 6 | FAILURE, 7 | ERROR, 8 | EXCEPTION, 9 | } 10 | -------------------------------------------------------------------------------- /bench/src/main/java/net/isucon/bench/Session.java: -------------------------------------------------------------------------------- 1 | package net.isucon.bench; 2 | 3 | import java.util.Map; 4 | import java.util.List; 5 | import java.util.ArrayList; 6 | import java.util.Enumeration; 7 | 8 | import java.net.HttpCookie; 9 | 10 | import org.eclipse.jetty.client.api.Request; 11 | import org.eclipse.jetty.client.api.Response; 12 | 13 | public class Session { 14 | private Parameter param; 15 | 16 | private List cookies; 17 | 18 | public Session(Parameter param) { 19 | this.param = param; 20 | this.cookies = new ArrayList(); 21 | } 22 | 23 | public Parameter param() { 24 | return param; 25 | } 26 | 27 | public void writeCookie(Request req) { 28 | List existing = req.getCookies(); 29 | synchronized(cookies) { 30 | for (HttpCookie cookie : cookies) { 31 | boolean exists = false; 32 | for (HttpCookie e : existing) { 33 | if (e.getName().equals(cookie.getName())) { 34 | e.setValue(cookie.getValue()); 35 | exists = true; 36 | break; 37 | } 38 | } 39 | if (! exists) { 40 | req.cookie(cookie); 41 | } 42 | } 43 | } 44 | } 45 | 46 | public void readCookie(Response res) { 47 | synchronized(cookies) { 48 | for (Enumeration i = res.getHeaders().getValues("Set-Cookie"); i.hasMoreElements();) { 49 | for (HttpCookie cookie : HttpCookie.parse(i.nextElement())) { 50 | boolean exists = false; 51 | for (HttpCookie e : cookies) { 52 | if (e.getName().equals(cookie.getName())) { 53 | e.setValue(cookie.getValue()); 54 | exists = true; 55 | break; 56 | } 57 | } 58 | if (! exists) 59 | cookies.add(cookie); 60 | } 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /bench/src/main/java/net/isucon/bench/State.java: -------------------------------------------------------------------------------- 1 | package net.isucon.bench; 2 | 3 | public class State { 4 | private boolean running; 5 | 6 | public State() { 7 | this.running = true; 8 | } 9 | 10 | public void init() { 11 | this.running = true; 12 | } 13 | 14 | public boolean isRunning() { 15 | return running; 16 | } 17 | 18 | public void finish() { 19 | this.running = false; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /bench/src/main/java/net/isucon/isucon5f/bench/Base.java: -------------------------------------------------------------------------------- 1 | package net.isucon.isucon5f.bench; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import java.util.HashMap; 6 | import java.util.Random; 7 | 8 | import java.net.URI; 9 | import java.net.URISyntaxException; 10 | 11 | import net.isucon.bench.Scenario; 12 | import net.isucon.bench.Parameter; 13 | import net.isucon.bench.Session; 14 | 15 | public class Base extends Scenario { 16 | private static long DEFAULT_HARD_TIMEOUT_WAIT = 5 * 1000; 17 | 18 | public Base(long softTimeout) { 19 | super(softTimeout, softTimeout + DEFAULT_HARD_TIMEOUT_WAIT); 20 | } 21 | 22 | protected Map formLogin(Session session) { 23 | I5FParameter p = (I5FParameter) session.param(); 24 | Map form = new HashMap(); 25 | 26 | form.put("email", p.email); 27 | form.put("password", p.password); 28 | return form; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /bench/src/main/java/net/isucon/isucon5f/bench/Full.java: -------------------------------------------------------------------------------- 1 | package net.isucon.isucon5f.bench; 2 | 3 | import java.util.List; 4 | import java.time.LocalDateTime; 5 | import java.time.temporal.ChronoUnit; 6 | 7 | import net.isucon.bench.Scenario; 8 | import net.isucon.bench.Step; 9 | import net.isucon.bench.Result; 10 | import net.isucon.bench.Parameter; 11 | import net.isucon.bench.Session; 12 | 13 | public class Full extends Scenario { 14 | private static final String PARAMETER_CLASS = "net.isucon.isucon5f.bench.I5FParameter"; 15 | 16 | private static long DURATION_MILLIS = 120 * 1000; 17 | private static long TERMINATE_MILLIS = 125 * 1000; 18 | 19 | public Full() { 20 | super(DURATION_MILLIS, TERMINATE_MILLIS); 21 | } 22 | 23 | @Override 24 | public String parameterClassName() { 25 | return PARAMETER_CLASS; 26 | } 27 | 28 | @Override 29 | public boolean complex() { 30 | return true; 31 | } 32 | 33 | @Override 34 | public Result finishHook(Result result) { 35 | long requests = result.requests; 36 | if (result.responses.exception * 100.0 / (requests * 1.0) >= 1.0) { 37 | result.addViolation("Too many exceptions", "通信エラー等の失敗が多過ぎます(1%以上)"); 38 | result.fail(); 39 | } 40 | if (result.responses.error * 100.0 / (requests * 1.0) >= 1.0) { 41 | result.addViolation("Too many errors", "ステータス 5xx のレスポンスが多過ぎます(1%以上)"); 42 | result.fail(); 43 | } 44 | if (result.responses.failure * 100.0 / (requests * 1.0) >= 5.0) { 45 | result.addViolation("Too many failures", "ステータス 4xx のレスポンスが多過ぎます(5%以上)"); 46 | result.fail(); 47 | } 48 | return result; 49 | } 50 | 51 | @Override 52 | public Step[] steps() { 53 | Step[] steps = new Step[3]; 54 | steps[0] = new Step(Init.class); 55 | steps[1] = new Step(Bootstrap.class); 56 | steps[2] = new Step( 57 | Checker.class, ModifyLoader.class, 58 | Load.class, Load.class, Load.class, Load.class, Load.class, Load.class, Load.class, Load.class, 59 | Load.class, Load.class, Load.class, Load.class, Load.class, Load.class, Load.class, Load.class, 60 | Load.class, Load.class, Load.class, Load.class, Load.class, Load.class, Load.class, Load.class, 61 | Load.class, Load.class, Load.class, Load.class, Load.class, Load.class, Load.class, Load.class, 62 | Load.class, Load.class, Load.class, Load.class, Load.class, Load.class, Load.class, Load.class, 63 | Load.class, Load.class, Load.class, Load.class, Load.class, Load.class, Load.class, Load.class 64 | ); 65 | 66 | return steps; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /bench/src/main/java/net/isucon/isucon5f/bench/I5FGivennames.java: -------------------------------------------------------------------------------- 1 | package net.isucon.isucon5f.bench; 2 | 3 | import java.util.Collections; 4 | import java.util.List; 5 | import java.util.ArrayList; 6 | import java.util.Map; 7 | import java.util.HashMap; 8 | 9 | import com.fasterxml.jackson.core.type.TypeReference; 10 | 11 | public class I5FGivennames extends I5FJsonData { 12 | private static String SOURCE_DIR_ENV_NAME = "ISUCON_BENCH_DATADIR"; 13 | private static String SOURCE_FILE_BASENAME = "givenname_queries_response.json"; 14 | 15 | public static Map map; 16 | public static List shuffled; 17 | private static int pos = 0; 18 | 19 | public static synchronized String getKey() { 20 | load(); 21 | String key = shuffled.get(pos); 22 | pos += 1; 23 | if (pos >= shuffled.size()) { 24 | pos = 0; 25 | } 26 | return key; 27 | } 28 | 29 | public static String getQuery(String key) { 30 | load(); 31 | I5FJsonData.NameEntry entry = map.get(key); 32 | if (entry == null) { 33 | System.err.println(String.format("Key not found for Surnames: '%s'", key)); 34 | return "CALL GameMaster"; 35 | } 36 | return map.get(key).query; 37 | } 38 | 39 | public static List getResult(String key) { 40 | load(); 41 | I5FJsonData.NameEntry entry = map.get(key); 42 | if (entry == null) { 43 | System.err.println(String.format("Key not found for Surnames: '%s'", key)); 44 | return Collections.emptyList(); 45 | } 46 | return map.get(key).result; 47 | } 48 | 49 | public static void load() { 50 | if (map != null) 51 | return; 52 | String sourcePath = System.getenv(SOURCE_DIR_ENV_NAME) + "/" + SOURCE_FILE_BASENAME; 53 | Map input = I5FJsonData.loadMap(sourcePath, new TypeReference>(){}); 54 | map = new HashMap(); 55 | shuffled = new ArrayList(); 56 | input.forEach((k,v) -> { 57 | map.put(k, v); 58 | shuffled.add(k); 59 | }); 60 | Collections.shuffle(shuffled); 61 | } 62 | } 63 | 64 | -------------------------------------------------------------------------------- /bench/src/main/java/net/isucon/isucon5f/bench/I5FJsonData.java: -------------------------------------------------------------------------------- 1 | package net.isucon.isucon5f.bench; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | import java.util.Map; 7 | import java.util.List; 8 | 9 | import com.fasterxml.jackson.databind.ObjectMapper; 10 | // import com.fasterxml.jackson.databind.JsonMappingException; 11 | import com.fasterxml.jackson.core.type.TypeReference; 12 | // import com.fasterxml.jackson.core.JsonParseException; 13 | 14 | public class I5FJsonData { 15 | protected static T loadMap(String path, TypeReference typeref) { 16 | try { 17 | ObjectMapper mapper = new ObjectMapper(); 18 | return mapper.readValue(new File(path), typeref); 19 | } catch (IOException e) { 20 | throw new RuntimeException("Failed to load json: " + path); 21 | } 22 | } 23 | 24 | protected static T loadList(String path, TypeReference typeref) { 25 | try { 26 | ObjectMapper mapper = new ObjectMapper(); 27 | return mapper.readValue(new File(path), typeref); 28 | } catch (IOException e) { 29 | throw new RuntimeException("Failed to load json: " + path); 30 | } 31 | } 32 | 33 | public static class NameElement { 34 | public String name; 35 | public String yomi; 36 | } 37 | 38 | public static class NameEntry { 39 | public String query; 40 | public List result; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /bench/src/main/java/net/isucon/isucon5f/bench/I5FSurnames.java: -------------------------------------------------------------------------------- 1 | package net.isucon.isucon5f.bench; 2 | 3 | import java.util.Collections; 4 | import java.util.List; 5 | import java.util.ArrayList; 6 | import java.util.Map; 7 | import java.util.HashMap; 8 | 9 | import com.fasterxml.jackson.core.type.TypeReference; 10 | 11 | public class I5FSurnames { 12 | private static String SOURCE_DIR_ENV_NAME = "ISUCON_BENCH_DATADIR"; 13 | private static String SOURCE_FILE_BASENAME = "surname_queries_response.json"; 14 | 15 | public static Map map; 16 | public static List shuffled; 17 | private static int pos = 0; 18 | 19 | public static synchronized String getKey() { 20 | load(); 21 | String key = shuffled.get(pos); 22 | pos += 1; 23 | if (pos >= shuffled.size()) { 24 | pos = 0; 25 | } 26 | return key; 27 | } 28 | 29 | public static String getQuery(String key) { 30 | load(); 31 | I5FJsonData.NameEntry entry = map.get(key); 32 | if (entry == null) { 33 | System.err.println(String.format("Key not found for Surnames: '%s'", key)); 34 | return "CALL GameMaster"; 35 | } 36 | return map.get(key).query; 37 | } 38 | 39 | public static List getResult(String key) { 40 | load(); 41 | I5FJsonData.NameEntry entry = map.get(key); 42 | if (entry == null) { 43 | System.err.println(String.format("Key not found for Surnames: '%s'", key)); 44 | return Collections.emptyList(); 45 | } 46 | return map.get(key).result; 47 | } 48 | 49 | public static void load() { 50 | if (map != null) 51 | return; 52 | String sourcePath = System.getenv(SOURCE_DIR_ENV_NAME) + "/" + SOURCE_FILE_BASENAME; 53 | Map input = I5FJsonData.loadMap(sourcePath, new TypeReference>(){}); 54 | map = new HashMap(); 55 | shuffled = new ArrayList(); 56 | input.forEach((k,v) -> { 57 | map.put(k, v); 58 | shuffled.add(k); 59 | }); 60 | Collections.shuffle(shuffled); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /bench/src/main/java/net/isucon/isucon5f/bench/I5FZipcodes.java: -------------------------------------------------------------------------------- 1 | package net.isucon.isucon5f.bench; 2 | 3 | import java.util.Collections; 4 | import java.util.Map; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.ArrayList; 8 | 9 | import com.fasterxml.jackson.core.type.TypeReference; 10 | 11 | public class I5FZipcodes { 12 | private static String SOURCE_DIR_ENV_NAME = "ISUCON_BENCH_DATADIR"; 13 | private static String SOURCE_FILE_BASENAME = "ken_all.json"; 14 | 15 | public static Map> map; 16 | public static List shuffled; 17 | private static int pos = 0; 18 | 19 | public static synchronized String getKey() { 20 | load(); 21 | String key = shuffled.get(pos); 22 | pos += 1; 23 | if (pos >= shuffled.size()) { 24 | pos = 0; 25 | } 26 | return key; 27 | } 28 | 29 | public static String address(String zipcode) { 30 | load(); 31 | List addresses = map.get(zipcode); 32 | if (addresses == null) 33 | throw new IllegalArgumentException("Argument zipcode does not exist in list: " + zipcode); 34 | return addresses.get(0); 35 | } 36 | 37 | public static void load() { 38 | if (map != null) 39 | return; 40 | String sourcePath = System.getenv(SOURCE_DIR_ENV_NAME) + "/" + SOURCE_FILE_BASENAME; 41 | map = I5FJsonData.loadMap(sourcePath, new TypeReference>>(){}); 42 | shuffled = new ArrayList(); 43 | map.forEach((k,v) -> { shuffled.add(k); }); 44 | Collections.shuffle(shuffled); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /bench/src/main/java/net/isucon/isucon5f/bench/Init.java: -------------------------------------------------------------------------------- 1 | package net.isucon.isucon5f.bench; 2 | 3 | import java.util.List; 4 | 5 | import net.isucon.bench.Scenario; 6 | import net.isucon.bench.Step; 7 | import net.isucon.bench.Result; 8 | import net.isucon.bench.Parameter; 9 | import net.isucon.bench.Session; 10 | 11 | public class Init extends Base { 12 | private static final String PARAMETER_CLASS = "net.isucon.isucon5f.bench.I5FParameter"; 13 | 14 | private static long DURATION_MILLIS = 33 * 1000; 15 | 16 | public Init() { 17 | super(DURATION_MILLIS); 18 | } 19 | 20 | @Override 21 | public String parameterClassName() { 22 | return PARAMETER_CLASS; 23 | } 24 | 25 | @Override 26 | public Result finishHook(Result result) { 27 | if (result.violations.size() > 0) 28 | result.fail(); 29 | return result; 30 | } 31 | 32 | @Override 33 | public void scenario(List originalSessions) { 34 | Session s = new Session(null); 35 | 36 | getAndCheck(s, "/initialize", "INITIALIZE DATA", (check) -> { 37 | check.isStatus(200); 38 | check.respondUntil(30L * 1000); 39 | }); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /bench/src/main/java/net/isucon/isucon5f/bench/Load.java: -------------------------------------------------------------------------------- 1 | package net.isucon.isucon5f.bench; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import java.util.HashMap; 6 | 7 | import java.net.URI; 8 | import java.net.URISyntaxException; 9 | 10 | import java.time.LocalDateTime; 11 | import java.time.temporal.ChronoUnit; 12 | import java.time.temporal.ChronoField; 13 | 14 | import net.isucon.bench.Scenario; 15 | import net.isucon.bench.Step; 16 | import net.isucon.bench.Result; 17 | import net.isucon.bench.Parameter; 18 | import net.isucon.bench.Session; 19 | 20 | public class Load extends Base { 21 | private static final String PARAMETER_CLASS = "net.isucon.isucon5f.bench.I5FParameter"; 22 | 23 | private static long DURATION_MILLIS = 60 * 1000; 24 | 25 | public Load() { 26 | super(DURATION_MILLIS); 27 | } 28 | 29 | @Override 30 | public String parameterClassName() { 31 | return PARAMETER_CLASS; 32 | } 33 | 34 | @Override 35 | public void scenario(List sessions) { 36 | System.err.println("Load"); 37 | 38 | while (true) { 39 | stopCheck(); 40 | Session s = pick(sessions); 41 | 42 | get(s, "/login"); 43 | get(s, "/css/bootstrap.min.css"); 44 | get(s, "/css/signin.css"); 45 | post(s, "/login", formLogin(s)); 46 | 47 | stopCheck(); 48 | 49 | get(s, "/"); 50 | get(s, "/css/bootstrap.min.css"); 51 | get(s, "/css/jumbotron-narrow.css"); 52 | get(s, "/js/jquery-1.11.3.js"); 53 | get(s, "/js/bootstrap.js"); 54 | get(s, "/js/airisu.js"); 55 | get(s, "/user.js"); 56 | 57 | stopCheck(); 58 | 59 | for (int i = 0 ; i < 10 ; i++) { 60 | get(s, "/data"); 61 | 62 | stopCheck(); 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /bench/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export ISUCON_BENCH_DATADIR=$(pwd)/json 4 | cat ../data/source.json | jq '.[0]' | gradle run -Pargs="net.isucon.isucon5f.bench.Full 127.0.0.1 -p 9292" 5 | -------------------------------------------------------------------------------- /data/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem 'faker' 4 | gem 'yajl-ruby', require: 'yajl' 5 | -------------------------------------------------------------------------------- /data/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | faker (1.5.0) 5 | i18n (~> 0.5) 6 | i18n (0.7.0) 7 | yajl-ruby (1.2.1) 8 | 9 | PLATFORMS 10 | ruby 11 | 12 | DEPENDENCIES 13 | faker 14 | yajl-ruby 15 | 16 | BUNDLED WITH 17 | 1.10.6 18 | -------------------------------------------------------------------------------- /data/gen_zipcode_json.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'csv' 4 | require 'yajl' 5 | 6 | KEN_ALL_CSV = File.expand_path("../../api/ken/x-ken-all.utf8.csv", __FILE__) 7 | DESTINATION = File.expand_path("../ken_all.json", __FILE__) 8 | 9 | data = {} 10 | 11 | CSV.foreach(KEN_ALL_CSV) do |row| 12 | zipcode = row[2] 13 | address = "#{row[6]} #{row[7]} #{row[8]}" 14 | data[zipcode] ||= [] 15 | data[zipcode] << address 16 | end 17 | 18 | open(DESTINATION, 'w') do |io| 19 | Yajl::Encoder.encode(data, io) 20 | end 21 | -------------------------------------------------------------------------------- /eventapp/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem "sinatra" 4 | gem "sinatra-contrib" 5 | gem "mysql2-cs-bind" 6 | gem "erubis" 7 | gem "unicorn" 8 | gem "foreman" 9 | -------------------------------------------------------------------------------- /eventapp/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | backports (3.6.6) 5 | erubis (2.7.0) 6 | foreman (0.78.0) 7 | thor (~> 0.19.1) 8 | kgio (2.10.0) 9 | multi_json (1.11.2) 10 | mysql2 (0.4.1) 11 | mysql2-cs-bind (0.0.6) 12 | mysql2 13 | rack (1.6.4) 14 | rack-protection (1.5.3) 15 | rack 16 | rack-test (0.6.3) 17 | rack (>= 1.0) 18 | raindrops (0.15.0) 19 | sinatra (1.4.6) 20 | rack (~> 1.4) 21 | rack-protection (~> 1.4) 22 | tilt (>= 1.3, < 3) 23 | sinatra-contrib (1.4.6) 24 | backports (>= 2.0) 25 | multi_json 26 | rack-protection 27 | rack-test 28 | sinatra (~> 1.4.0) 29 | tilt (>= 1.3, < 3) 30 | thor (0.19.1) 31 | tilt (2.0.1) 32 | unicorn (4.9.0) 33 | kgio (~> 2.6) 34 | rack 35 | raindrops (~> 0.7) 36 | 37 | PLATFORMS 38 | ruby 39 | 40 | DEPENDENCIES 41 | erubis 42 | foreman 43 | mysql2-cs-bind 44 | sinatra 45 | sinatra-contrib 46 | unicorn 47 | -------------------------------------------------------------------------------- /eventapp/Procfile: -------------------------------------------------------------------------------- 1 | web: bundle exec unicorn -c ./unicorn_config.rb 2 | mon: bundle exec ruby ./update_scores.rb -------------------------------------------------------------------------------- /eventapp/config.ru: -------------------------------------------------------------------------------- 1 | require_relative './app.rb' 2 | 3 | run Isucon5Portal::WebApp 4 | -------------------------------------------------------------------------------- /eventapp/lib/score.rb: -------------------------------------------------------------------------------- 1 | module Isucon5Portal 2 | module Score 3 | def self.calculate(result) 4 | # result = { 5 | # "valid" : false, 6 | # "requests" : 5, 7 | # "elapsed" : 413, 8 | # "done" : "BootstrapChecker", 9 | # "responses" : { 10 | # "success" : 2, 11 | # "redirect" : 1, 12 | # "failure" : 0, 13 | # "error" : 0, 14 | # "exception" : 2 15 | # }, 16 | # "violations" : [ 17 | # { 18 | # "type" : "HttpResponseException", 19 | # "description" : "HTTP protocol violation: Authentication challenge without WWW-Authenticate header", 20 | # "number" : 2 21 | # }, 22 | # { 23 | # "type" : "SHOULD LOGIN AT FIRST", 24 | # "description" : "未ログインでトップページへのアクセスが正しいリダイレクトになっていません", 25 | # "number" : 1 26 | # } 27 | # ] 28 | # } 29 | base_score = result["responses"]["success"] + result["responses"]["redirect"] * 0.1 30 | minus_score = result["responses"]["error"] * 10 + result["responses"]["exception"] * 20 31 | 32 | too_slow_penalty = 0 33 | too_slow_responses = result["violations"].select{|v| v["description"] =~ /アプリケーションが \d+ ミリ秒以内に応答しませんでした/ } 34 | if too_slow_responses.size > 0 35 | too_slow_penalty = too_slow_responses.map{|v| v["number"]}.inject(&:+) * 100 36 | end 37 | 38 | score = base_score - minus_score - too_slow_penalty 39 | if score < 0 40 | score = 0 41 | end 42 | 43 | summary = (result["valid"] ? "success" : "fail") 44 | if score < 1 45 | summary = "fail" 46 | end 47 | return summary, score 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /eventapp/public/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isucon/isucon5-final/981f7721e94e655280d71f70f64fa13b94181128/eventapp/public/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /eventapp/public/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isucon/isucon5-final/981f7721e94e655280d71f70f64fa13b94181128/eventapp/public/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /eventapp/public/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isucon/isucon5-final/981f7721e94e655280d71f70f64fa13b94181128/eventapp/public/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /eventapp/public/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isucon/isucon5-final/981f7721e94e655280d71f70f64fa13b94181128/eventapp/public/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /eventapp/public/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /eventapp/scripts/hosts.txt: -------------------------------------------------------------------------------- 1 | 203.104.208.171 isu01a 2 | 203.104.208.172 isu01b 3 | 203.104.208.173 isu01c 4 | 203.104.208.174 isu02a 5 | 203.104.208.175 isu02b 6 | 203.104.208.176 isu02c 7 | 203.104.208.177 isu03a 8 | 203.104.208.178 isu03b 9 | 203.104.208.179 isu03c 10 | 203.104.208.180 isu04a 11 | 203.104.208.181 isu04b 12 | 203.104.208.182 isu04c 13 | 203.104.208.183 isu05a 14 | 203.104.208.184 isu05b 15 | 203.104.208.185 isu05c 16 | 203.104.208.186 isu06a 17 | 203.104.208.187 isu06b 18 | 203.104.208.188 isu06c 19 | 203.104.208.189 isu07a 20 | 203.104.208.190 isu07b 21 | 203.104.208.191 isu07c 22 | 203.104.208.192 isu08a 23 | 203.104.208.193 isu08b 24 | 203.104.208.194 isu08c 25 | 203.104.208.195 isu09a 26 | 203.104.208.196 isu09b 27 | 203.104.208.197 isu09c 28 | 203.104.208.198 isu10a 29 | 203.104.208.199 isu10b 30 | 203.104.208.200 isu10c 31 | 203.104.208.201 isu11a 32 | 203.104.208.202 isu11b 33 | 203.104.208.203 isu11c 34 | 203.104.208.204 isu12a 35 | 203.104.208.205 isu12b 36 | 203.104.208.206 isu12c 37 | 203.104.208.207 isu13a 38 | 203.104.208.208 isu13b 39 | 203.104.208.209 isu13c 40 | 203.104.208.210 isu14a 41 | 203.104.208.211 isu14b 42 | 203.104.208.212 isu14c 43 | 203.104.208.213 isu15a 44 | 203.104.208.214 isu15b 45 | 203.104.208.215 isu15c 46 | 203.104.208.216 isu16a 47 | 203.104.208.217 isu16b 48 | 203.104.208.218 isu16c 49 | 203.104.208.219 isu17a 50 | 203.104.208.220 isu17b 51 | 203.104.208.221 isu17c 52 | 203.104.208.222 isu18a 53 | 203.104.208.223 isu18b 54 | 203.104.208.224 isu18c 55 | 203.104.208.225 isu19a 56 | 203.104.208.226 isu19b 57 | 203.104.208.227 isu19c 58 | 203.104.208.228 isu20a 59 | 203.104.208.229 isu20b 60 | 203.104.208.230 isu20c 61 | 203.104.208.231 isu21a 62 | 203.104.208.232 isu21b 63 | 203.104.208.233 isu21c 64 | 203.104.208.234 isu22a 65 | 203.104.208.235 isu22b 66 | 203.104.208.236 isu22c 67 | 203.104.208.237 isu23a 68 | 203.104.208.238 isu23b 69 | 203.104.208.239 isu23c 70 | 203.104.208.240 isu24a 71 | 203.104.208.241 isu24b 72 | 203.104.208.242 isu24c 73 | 203.104.208.243 isu25a 74 | 203.104.208.244 isu25b 75 | 203.104.208.245 isu25c 76 | 203.104.208.246 isu26a 77 | 203.104.208.247 isu26b 78 | 203.104.208.248 isu26c 79 | 203.104.208.249 isu27a 80 | 203.104.208.250 isu27b 81 | 203.104.208.251 isu27c 82 | 203.104.208.252 isu28a 83 | 203.104.208.253 isu28b 84 | 203.104.208.254 isu28c 85 | -------------------------------------------------------------------------------- /eventapp/scripts/load_hosts.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'json' 4 | 5 | data = {} 6 | (1..28).each do |n| 7 | num = sprintf("%02d", n) 8 | data[num] = {} 9 | end 10 | 11 | File.open("./hosts.txt") do |f| 12 | f.readlines.each do |line| 13 | ipaddr, hostname = line.chomp.split(/\s+/) 14 | hostname =~ /isu(\d{2})[abc]/ 15 | team_num = $1 16 | data[team_num][hostname] = ipaddr 17 | end 18 | end 19 | 20 | data.keys.each do |key| 21 | puts key + "\t" + data[key].to_json 22 | end 23 | -------------------------------------------------------------------------------- /eventapp/sql/schema.sql: -------------------------------------------------------------------------------- 1 | DROP DATABASE IF EXISTS isucon5fportal; 2 | 3 | CREATE DATABASE IF NOT EXISTS isucon5fportal; 4 | 5 | use isucon5fportal; 6 | 7 | CREATE TABLE IF NOT EXISTS teams ( 8 | `id` int NOT NULL AUTO_INCREMENT PRIMARY KEY, 9 | `team` varchar(128) NOT NULL UNIQUE, 10 | `password` varchar(32) NOT NULL, 11 | `account` varchar(128) NOT NULL UNIQUE, 12 | `benchgroup` int NOT NULL, 13 | `priv` int NOT NULL, -- 0:organizer, 1:teams, 2:audience 14 | `destination` varchar(32) DEFAULT NULL, 15 | `ipaddrs` text DEFAULT NULL 16 | ) DEFAULT CHARSET=utf8mb4; 17 | 18 | CREATE TABLE IF NOT EXISTS queue ( 19 | `id` int NOT NULL AUTO_INCREMENT PRIMARY KEY, 20 | `team_id` int NOT NULL, 21 | `benchgroup` int NOT NULL, 22 | `status` varchar(16) NOT NULL, -- waiting, running, submitted, done 23 | `ip_address` varchar(32) NOT NULL, 24 | `testset_id` int NOT NULL, 25 | `acked_at` timestamp DEFAULT '0000-00-00 00:00:00', 26 | `bench_node` varchar(64) DEFAULT NULL, 27 | `submitted_at` timestamp DEFAULT '0000-00-00 00:00:00', 28 | `json` text 29 | ) DEFAULT CHARSET=utf8mb4; 30 | 31 | CREATE TABLE IF NOT EXISTS scores ( 32 | `id` int NOT NULL AUTO_INCREMENT PRIMARY KEY, 33 | `team_id` int NOT NULL, 34 | `summary` varchar(32) NOT NULL, -- success, fail 35 | `score` int NOT NULL, 36 | `submitted_at` timestamp, 37 | `json` text 38 | ) DEFAULT CHARSET=utf8mb4; 39 | 40 | CREATE TABLE IF NOT EXISTS highscores ( 41 | `team_id` int NOT NULL PRIMARY KEY, 42 | `score` int NOT NULL, 43 | `submitted_at` timestamp 44 | ) DEFAULT CHARSET=utf8mb4; 45 | 46 | CREATE TABLE IF NOT EXISTS testsets ( 47 | `id` int NOT NULL AUTO_INCREMENT PRIMARY KEY, 48 | `json` mediumtext 49 | ) DEFAULT CHARSET=utf8mb4; 50 | 51 | CREATE TABLE IF NOT EXISTS messages ( 52 | `id` int NOT NULL AUTO_INCREMENT PRIMARY KEY, 53 | -- http://getbootstrap.com/components/#alerts 54 | `priority` varchar(16) DEFAULT 'alert-info', -- 'alert-success', 'alert-info', 'alert-warning', 'alert-danger' 55 | `content` TEXT NOT NULL, 56 | `show_at` timestamp NOT NULL, 57 | `hide_at` timestamp NOT NULL 58 | ) DEFAULT CHARSET=utf8mb4; 59 | -------------------------------------------------------------------------------- /eventapp/unicorn_config.rb: -------------------------------------------------------------------------------- 1 | worker_processes 24 2 | preload_app true 3 | listen 8080 4 | pid "/home/isucon/isucon5-final/eventapp/unicorn.pid" 5 | -------------------------------------------------------------------------------- /eventapp/update_scores.rb: -------------------------------------------------------------------------------- 1 | require_relative "lib/score" 2 | 3 | require "mysql2-cs-bind" 4 | require "json" 5 | 6 | client = Mysql2::Client.new( 7 | host: 'localhost', 8 | port: nil, 9 | username: 'root', 10 | password: nil, 11 | database: 'isucon5fportal', 12 | reconnect: true, 13 | ) 14 | client.query_options.merge!(symbolize_keys: true) 15 | 16 | while true 17 | sleep 5 18 | 19 | begin 20 | queue_entry_query = "SELECT id, team_id, status, acked_at, submitted_at, json FROM queue WHERE status=? " 21 | 22 | # fetch submitted queries, and post score 23 | client.xquery(queue_entry_query, "submitted").each do |row| 24 | result = JSON.parse(row[:json]) rescue nil 25 | summary = "fail" 26 | score = 0 27 | if result 28 | summary, score = Isucon5Portal::Score.calculate(result) 29 | end 30 | insert_score_query = "INSERT INTO scores (team_id,summary,score,submitted_at,json) VALUES (?,?,?,?,?)" 31 | client.xquery(insert_score_query, row[:team_id], summary, score, row[:submitted_at], row[:json]) 32 | # ignore duplicated insert ... 33 | if summary == "success" && score > 0 34 | highscore = client.xquery("SELECT score FROM highscores WHERE team_id=?", row[:team_id]).first() 35 | if highscore.nil? 36 | client.xquery("INSERT INTO highscores (team_id, score, submitted_at) VALUES (?,?,?)", row[:team_id], score, row[:submitted_at]) 37 | elsif highscore[:score] < score 38 | client.xquery("UPDATE highscores SET score=?, submitted_at=? WHERE team_id=?", score, row[:submitted_at], row[:team_id]) 39 | end 40 | end 41 | client.xquery("UPDATE queue SET status='done' WHERE id=? ", row[:id]) 42 | end 43 | 44 | # fetch queue entries stays in 'running' too long to retry... 45 | client.xquery(queue_entry_query, "running").each do |row| 46 | if row[:acked_at] + 180 < Time.now 47 | # 5min is too long to wait for bench: does something go wrong? -> retry 48 | client.xquery("UPDATE queue SET status='waiting' WHERE id=? ", row[:id]) 49 | end 50 | end 51 | rescue => e 52 | STDERR.puts "Exception #{e.class}: #{e.message}" 53 | e.backtrace.each do |t| 54 | STDERR.puts "\t" + t 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /eventapp/views/layout.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ISUCON5 決勝ポータル 5 | 6 | 7 | 8 | 9 | 10 | 30 | 31 |
32 | 33 | <%== yield %> 34 | 35 |
36 | 37 | <% if team_id %> 38 | 41 | <% end %> 42 | 43 | 44 | 45 | 46 | <% if team_id && enable_actions %> 47 | 48 | <% end %> 49 | 50 | 51 | -------------------------------------------------------------------------------- /eventapp/views/login.erb: -------------------------------------------------------------------------------- 1 |
2 |

ISUCON5 決勝ポータル

3 |

参加者以外の方は guest/guest で参照専用ログインが可能です

4 |
5 | 6 |
7 |
8 |
9 |
10 |
11 |
12 | 13 | 14 |
15 |
16 | 17 | 18 |
19 | 20 |
21 |
22 |
23 |
24 |
25 | -------------------------------------------------------------------------------- /eventapp/views/team.erb: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 |

チーム情報の更新

7 | 8 |
9 |
10 |
11 | 12 | 13 |
14 |
15 | 16 | 17 |
18 |
19 | 20 | 26 |
27 |
28 | 29 | 30 |
31 | 32 |
33 |
34 |
35 | -------------------------------------------------------------------------------- /provisioning/.gitignore: -------------------------------------------------------------------------------- 1 | Gemfile.lock 2 | */tmp 3 | -------------------------------------------------------------------------------- /provisioning/all-in-one/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'thor' 4 | -------------------------------------------------------------------------------- /provisioning/all-in-one/ansible/00_devel.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: no 4 | tasks: 5 | - copy: src=../files/sources.list dest=/etc/apt/sources.list owner=root mode=644 6 | - apt: name=python-selinux state=present update_cache=true 7 | - service: name=apparmor enabled=no state=stopped 8 | - apt: name=git state=present 9 | - apt: name=gcc state=present 10 | - apt: name=patch state=present 11 | - apt: name=autoconf state=present 12 | - apt: name=automake state=present 13 | - apt: name=bison state=present 14 | - apt: name=build-essential 15 | - apt: name=libssl-dev state=present 16 | - apt: name=libyaml-dev state=present 17 | - apt: name=libreadline6-dev state=present 18 | - apt: name=zlib1g-dev state=present 19 | - apt: name=libncurses5-dev state=present 20 | - apt: name=libffi-dev state=present 21 | - apt: name=libgdbm3 state=present 22 | - apt: name=libgdbm-dev state=present 23 | - apt: name=libmysqlclient-dev state=present 24 | - apt: name=libpq-dev state=present 25 | - apt: name=libcurl4-openssl-dev state=present 26 | - apt: name=libjpeg-turbo8 state=present 27 | - apt: name=libjpeg-turbo8-dev state=present 28 | - apt: name=libpng12-0 state=present 29 | - apt: name=libpng12-dev state=present 30 | - apt: name=libmcrypt4 state=present 31 | - apt: name=libmcrypt-dev state=present 32 | - apt: name=libtidy-0.99-0 state=present 33 | - apt: name=libtidy-dev state=present 34 | - apt: name=libxml2-dev state=present 35 | - apt: name=libxslt1-dev state=present 36 | - apt: name=readline-common state=present 37 | - apt: name=re2c state=present 38 | # for node-install 39 | - apt: name=curl state=present 40 | # for php --with-openssl 41 | - apt: name=pkg-config 42 | -------------------------------------------------------------------------------- /provisioning/all-in-one/ansible/01_isucon_base.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: no 4 | tasks: 5 | - name: change timezone to JST 6 | shell: cp -p /usr/share/zoneinfo/Japan /etc/localtime 7 | - group: name=wheel 8 | - user: name=isucon groups=wheel 9 | - copy: src=../files/bashrc dest=/home/isucon/.bashrc owner=isucon mode=755 10 | - lineinfile: dest=/etc/sudoers state=present regexp='^%wheel ALL\=' line='%wheel ALL=(ALL) NOPASSWD:ALL' validate='visudo -cf %s' 11 | -------------------------------------------------------------------------------- /provisioning/all-in-one/ansible/02_xbuild.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | sudo: yes 4 | sudo_user: isucon 5 | gather_facts: no 6 | tasks: 7 | - git: 8 | repo=https://github.com/tagomoris/xbuild.git 9 | dest=/home/isucon/.xbuild 10 | update=yes 11 | # ruby 12 | - command: /home/isucon/.xbuild/ruby-install 2.2.3 /home/isucon/.local/ruby 13 | args: 14 | creates: /home/isucon/.local/ruby/bin/ruby 15 | # node 16 | - command: /home/isucon/.xbuild/node-install v4.1.1 /home/isucon/.local/node 17 | args: 18 | creates: /home/isucon/.local/node/bin/node 19 | # python3 20 | - command: /home/isucon/.xbuild/python-install 3.4.3 /home/isucon/.local/python3 21 | args: 22 | creates: /home/isucon/.local/python3/bin/python 23 | # perl 24 | - command: /home/isucon/.xbuild/perl-install 5.20.2 /home/isucon/.local/perl 25 | args: 26 | creates: /home/isucon/.local/perl/bin/perl 27 | # php 28 | - command: /home/isucon/.xbuild/php-install 5.6.13 /home/isucon/.local/php -- --with-pear --with-openssl --with-pdo-pgsql 29 | args: 30 | creates: /home/isucon/.local/php/bin/php 31 | - copy: src=../files/php.ini dest=/home/isucon/.local/php/etc/php.ini owner=isucon mode=644 32 | # golang 33 | - command: /home/isucon/.xbuild/go-install 1.5 /home/isucon/.local/go 34 | args: 35 | creates: /home/isucon/.local/go/bin/go 36 | # scala 37 | - shell: curl http://downloads.typesafe.com/scala/2.11.7/scala-2.11.7.tgz | (cd /home/isucon/.local && tar xzf -) 38 | args: 39 | creates: /home/isucon/.local/scala-2.11.7/bin/scala 40 | - file: src=/home/isucon/.local/scala-2.11.7 dest=/home/isucon/.local/scala state=link 41 | 42 | - hosts: all 43 | gather_facts: no 44 | tasks: 45 | - apt_repository: repo='ppa:webupd8team/java' 46 | - name: Autoaccept license for Java8 47 | debconf: name='oracle-java8-installer' question='shared/accepted-oracle-license-v1-1' value='true' vtype='select' 48 | - apt: name=oracle-java8-installer update_cache=yes 49 | - apt: name=ca-certificates 50 | - apt: name=oracle-java8-set-default 51 | - apt_repository: repo='ppa:cwchien/gradle' 52 | - apt: name=gradle-2.8 update_cache=yes 53 | - file: src=/usr/lib/jvm/java-8-oracle dest=/usr/lib/jvm/default-java owner=root state=link 54 | -------------------------------------------------------------------------------- /provisioning/all-in-one/ansible/03_middleware.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: no 4 | tasks: 5 | - apt: name=nginx state=present 6 | - service: name=nginx state=running enabled=true 7 | - copy: src=../files/nginx.conf dest=/etc/nginx/nginx.conf owner=root mode=644 8 | notify: 9 | - reload nginx 10 | - copy: src=../files/nginx.php.conf dest=/etc/nginx/nginx.php.conf owner=root mode=644 11 | - apt: name=python-psycopg2 state=present 12 | - apt_key: url=https://www.postgresql.org/media/keys/ACCC4CF8.asc state=present 13 | - apt_repository: repo='deb http://apt.postgresql.org/pub/repos/apt/ trusty-pgdg main' state=present update_cache=yes 14 | - apt: name=postgresql-9.4 state=present 15 | - apt: name=postgresql-contrib-9.4 state=present 16 | - apt: name=postgresql-client-9.4 state=present 17 | - name: copy postgresql configurations 18 | copy: src=../files/postgresql.conf dest=/etc/postgresql/9.4/main/postgresql.conf owner=postgres group=postgres mode=644 19 | notify: 20 | - restart postgresql 21 | - name: copy postgres connection controls 22 | copy: src=../files/pg_hba.conf dest=/etc/postgresql/9.4/main/pg_hba.conf owner=postgres group=postgres mode=640 23 | notify: 24 | - restart postgresql 25 | - service: name=postgresql state=running enabled=true 26 | handlers: 27 | - name: restart postgresql 28 | action: service name=postgresql state=restarted 29 | - name: reload nginx 30 | action: service name=nginx state=restarted 31 | 32 | - hosts: all 33 | gather_facts: no 34 | sudo: yes 35 | sudo_user: postgres 36 | tasks: 37 | - postgresql_user: name=isucon 38 | - postgresql_db: name=isucon5f owner=isucon encoding=utf8 template=template0 39 | - postgresql_ext: name=pgcrypto db=isucon5f 40 | 41 | - hosts: all 42 | gather_facts: no 43 | sudo: yes 44 | sudo_user: isucon 45 | tasks: 46 | - copy: src=../files/schema.sql dest=/tmp/schema.sql 47 | - shell: cat /tmp/schema.sql | psql isucon5f 48 | - command: rm /tmp/schema.sql 49 | -------------------------------------------------------------------------------- /provisioning/all-in-one/ansible/05_api_servers.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: no 4 | sudo: yes 5 | sudo_user: isucon 6 | tasks: 7 | - file: path=/home/isucon/.ssh state=directory owner=isucon mode=755 8 | - git: 9 | repo=https://github.com/isucon/isucon5-final.git 10 | dest=/home/isucon/isucon5-final 11 | - copy: src=../files/env.sh dest=/home/isucon/env.sh owner=isucon mode=755 12 | 13 | - name: KEN_ALL API 14 | shell: PATH=/home/isucon/.local/ruby/bin:$PATH bundle install 15 | args: 16 | chdir: /home/isucon/isucon5-final/api/ken 17 | 18 | - name: PerfectSequrity API 19 | shell: PATH=/home/isucon/.local/node/bin:$PATH npm install 20 | args: 21 | chdir: /home/isucon/isucon5-final/api/perfect_security 22 | 23 | - name: Search Name API 24 | shell: gradle wrapper 25 | args: 26 | chdir: /home/isucon/isucon5-final/api/search-name 27 | 28 | - name: Tenki API 29 | shell: PATH=/home/isucon/.local/go/bin:$PATH GOROOT=/home/isucon/.local/go GOPATH=/home/isucon/isucon5-final/api/go go build 30 | args: 31 | chdir: /home/isucon/isucon5-final/api/go/tenki 32 | 33 | - hosts: all 34 | gather_facts: no 35 | tasks: 36 | - apt: name=supervisor state=present 37 | # In ubuntu default /etc/supervisor/supervisord.conf 38 | # [include] 39 | # files = /etc/supervisor/conf.d/*.conf 40 | - copy: src=../files/supervisor.ken.conf dest=/etc/supervisor/conf.d/ken.conf 41 | - supervisorctl: name=ken state=present 42 | - supervisorctl: name=ken state=restarted 43 | 44 | - copy: src=../files/supervisor.perfect_security.conf dest=/etc/supervisor/conf.d/perfect_security.conf 45 | - supervisorctl: name=perfect_security state=present 46 | - supervisorctl: name=perfect_security state=restarted 47 | 48 | - copy: src=../files/supervisor.search-name.conf dest=/etc/supervisor/conf.d/search-name.conf 49 | - supervisorctl: name=search-name state=present 50 | - supervisorctl: name=search-name state=restarted 51 | 52 | - copy: src=../files/supervisor.tenki.conf dest=/etc/supervisor/conf.d/tenki.conf 53 | - supervisorctl: name=tenki state=present 54 | - supervisorctl: name=tenki state=restarted 55 | -------------------------------------------------------------------------------- /provisioning/all-in-one/ansible/06_deploy_bench_tool.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: no 4 | sudo: yes 5 | sudo_user: isucon 6 | tasks: 7 | - file: path=/home/isucon/.ssh state=directory owner=isucon mode=755 8 | - git: 9 | repo=https://github.com/isucon/isucon5-final.git 10 | dest=/home/isucon/isucon5-final 11 | - copy: src=../files/env.sh dest=/home/isucon/env.sh owner=isucon mode=755 12 | - name: ruby 13 | shell: PATH=/home/isucon/.local/ruby/bin:$PATH bundle install 14 | args: 15 | chdir: /home/isucon/isucon5-final/bench 16 | - name: java build 17 | shell: gradle compileJava 18 | args: 19 | chdir: /home/isucon/isucon5-final/bench 20 | -------------------------------------------------------------------------------- /provisioning/all-in-one/ansible/_cleanup.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: guests:extras 3 | gather_facts: no 4 | tasks: 5 | - shell: rm -rf /tmp/*; true 6 | - file: state=absent path=/home/isucon/.ssh/deploy_id_rsa 7 | - file: path=/root/.ansible state=absent 8 | - file: path=/root/.bash_history state=absent 9 | - file: path=/root/.viminfo state=absent 10 | - file: path=/home/isucon/.bash_history state=absent 11 | - file: path=/home/isucon/.viminfo state=absent 12 | -------------------------------------------------------------------------------- /provisioning/all-in-one/files/bashrc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ -f /etc/bashrc ]; then 3 | . /etc/bashrc 4 | fi 5 | 6 | export PATH=/usr/local/bin:$PATH 7 | export PATH=/home/isucon/.local/ruby/bin:$PATH 8 | export PATH=/home/isucon/.local/node/bin:$PATH 9 | export PATH=/home/isucon/.local/python3/bin:$PATH 10 | export PATH=/home/isucon/.local/perl/bin:$PATH 11 | export PATH=/home/isucon/.local/php/bin:$PATH 12 | export PATH=/home/isucon/.local/php/sbin:$PATH 13 | export PATH=/home/isucon/.local/go/bin:$PATH 14 | export GOROOT=/home/isucon/.local/go 15 | export GOPATH=/home/isucon/webapp/go 16 | export PATH=/home/isucon/.local/scala/bin:$PATH 17 | -------------------------------------------------------------------------------- /provisioning/all-in-one/files/env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | export PATH=/usr/local/bin:/home/isucon/.local/ruby/bin:/home/isucon/.local/node/bin:/home/isucon/.local/python3/bin:/home/isucon/.local/perl/bin:/home/isucon/.local/php/bin:/home/isucon/.local/php/sbin:/home/isucon/.local/go/bin:/home/isucon/.local/scala/bin:$PATH 3 | export GOPATH=/home/isucon/gocode 4 | export _JAVA_OPTIONS="-Dfile.encoding=UTF-8" 5 | 6 | exec $* 7 | -------------------------------------------------------------------------------- /provisioning/all-in-one/files/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | 3 | events { 4 | worker_connections 1024; 5 | } 6 | 7 | http { 8 | upstream app { 9 | server 127.0.0.1:8080; 10 | } 11 | 12 | server { 13 | location / { 14 | proxy_set_header Host $host; 15 | proxy_pass http://app; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /provisioning/all-in-one/files/nginx.php.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | 3 | events { 4 | worker_connections 1024; 5 | } 6 | 7 | http { 8 | include /etc/nginx/mime.types; 9 | types_hash_max_size 2048; 10 | 11 | upstream php-fpm { 12 | server 127.0.0.1:8080; 13 | } 14 | 15 | server { 16 | location ~ ^/(css|fonts|js) { 17 | root /home/isucon/webapp/static; 18 | } 19 | 20 | location / { 21 | root /home/isucon/webapp/php; 22 | 23 | fastcgi_pass php-fpm; 24 | fastcgi_index index.php; 25 | fastcgi_read_timeout 120; 26 | 27 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 28 | fastcgi_param QUERY_STRING $query_string; 29 | fastcgi_param REQUEST_METHOD $request_method; 30 | fastcgi_param CONTENT_TYPE $content_type; 31 | fastcgi_param CONTENT_LENGTH $content_length; 32 | 33 | fastcgi_param SCRIPT_NAME $fastcgi_script_name; 34 | fastcgi_param REQUEST_URI $request_uri; 35 | fastcgi_param DOCUMENT_URI $document_uri; 36 | fastcgi_param DOCUMENT_ROOT $document_root; 37 | fastcgi_param SERVER_PROTOCOL $server_protocol; 38 | fastcgi_param HTTPS $https if_not_empty; 39 | 40 | fastcgi_param GATEWAY_INTERFACE CGI/1.1; 41 | fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; 42 | 43 | fastcgi_param REMOTE_ADDR $http_x_forwarded_for; 44 | fastcgi_param REMOTE_PORT $remote_port; 45 | fastcgi_param SERVER_ADDR $server_addr; 46 | fastcgi_param SERVER_PORT $server_port; 47 | fastcgi_param SERVER_NAME $server_name; 48 | 49 | fastcgi_param REDIRECT_STATUS 200; 50 | 51 | rewrite ^(.*)$ /index.php?$1 break; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /provisioning/all-in-one/files/pg_hba.conf: -------------------------------------------------------------------------------- 1 | local all postgres peer 2 | local all all peer 3 | host all all 127.0.0.1/32 trust 4 | host all all ::1/128 trust 5 | -------------------------------------------------------------------------------- /provisioning/all-in-one/files/schema.sql: -------------------------------------------------------------------------------- 1 | -- CREATE USER isucon; 2 | -- CREATE DATABASE isucon5f OWNER isucon ENCODING 'utf8'; 3 | 4 | -- \connect isucon5f 5 | 6 | CREATE TYPE grades AS ENUM ('micro', 'small', 'standard', 'premium'); 7 | 8 | CREATE TABLE users ( 9 | id SERIAL PRIMARY KEY, 10 | email VARCHAR(256) NOT NULL, 11 | salt VARCHAR(32) NOT NULL, 12 | passhash bytea NOT NULL, 13 | grade grades 14 | ); 15 | 16 | -- CREATE EXTENSION pgcrypto; 17 | 18 | CREATE TYPE token_types AS ENUM ('header', 'param'); 19 | 20 | CREATE TABLE endpoints ( 21 | service VARCHAR(32) NOT NULL PRIMARY KEY, 22 | meth VARCHAR(16) NOT NULL, 23 | token_type token_types, 24 | token_key VARCHAR(64), 25 | uri TEXT 26 | ); 27 | 28 | CREATE TABLE subscriptions ( 29 | user_id INTEGER REFERENCES users (id) NOT NULL PRIMARY KEY, 30 | arg TEXT 31 | ); 32 | -------------------------------------------------------------------------------- /provisioning/all-in-one/files/supervisor.golang.conf: -------------------------------------------------------------------------------- 1 | [program:golang] 2 | directory=/home/isucon/webapp/golang 3 | command=/home/isucon/env.sh ./app 4 | user=isucon 5 | stdout_logfile=/tmp/isucon.golang.log 6 | stderr_logfile=/tmp/isucon.golang.log 7 | autostart=false 8 | -------------------------------------------------------------------------------- /provisioning/all-in-one/files/supervisor.java.conf: -------------------------------------------------------------------------------- 1 | [program:java] 2 | directory=/home/isucon/webapp/java 3 | command=/home/isucon/env.sh java -Djava.security.egd=file:/dev/./urandom -jar target/isucon5f-0.0.1-SNAPSHOT.jar --server.port=8080 4 | user=isucon 5 | stdout_logfile=/tmp/isucon.java.log 6 | stderr_logfile=/tmp/isucon.java.log 7 | autostart=false 8 | -------------------------------------------------------------------------------- /provisioning/all-in-one/files/supervisor.ken.conf: -------------------------------------------------------------------------------- 1 | [program:ken] 2 | directory=/home/isucon/isucon5-final/api/ken 3 | command=/home/isucon/env.sh bundle exec unicorn -c ./unicorn_config_all.rb 4 | user=isucon 5 | stdout_logfile=/tmp/api.ken.log 6 | stderr_logfile=/tmp/api.ken.log 7 | autostart=true 8 | -------------------------------------------------------------------------------- /provisioning/all-in-one/files/supervisor.node.conf: -------------------------------------------------------------------------------- 1 | [program:node] 2 | directory=/home/isucon/webapp/node 3 | command=/home/isucon/env.sh node app.js 4 | user=isucon 5 | stdout_logfile=/tmp/isucon.node.log 6 | stderr_logfile=/tmp/isucon.node.log 7 | autostart=false 8 | -------------------------------------------------------------------------------- /provisioning/all-in-one/files/supervisor.perfect_security.conf: -------------------------------------------------------------------------------- 1 | [program:perfect_security] 2 | directory=/home/isucon/isucon5-final/api/perfect_security 3 | command=/home/isucon/env.sh node index.js 4 | user=isucon 5 | stdout_logfile=/tmp/api.perfect_security.log 6 | stderr_logfile=/tmp/api.perfect_security.log 7 | autostart=true 8 | -------------------------------------------------------------------------------- /provisioning/all-in-one/files/supervisor.perl.conf: -------------------------------------------------------------------------------- 1 | [program:perl] 2 | directory=/home/isucon/webapp/perl 3 | command=/home/isucon/env.sh carton exec -- plackup -s Starman -p 8080 --workers 4 --disable-keepalive app.psgi 4 | user=isucon 5 | stdout_logfile=/tmp/isucon.perl.log 6 | stderr_logfile=/tmp/isucon.perl.log 7 | autostart=false 8 | -------------------------------------------------------------------------------- /provisioning/all-in-one/files/supervisor.php.conf: -------------------------------------------------------------------------------- 1 | [program:php] 2 | directory=/home/isucon/webapp/php 3 | command=/home/isucon/env.sh php-fpm -y php-fpm.conf 4 | user=isucon 5 | stdout_logfile=/tmp/isucon.php.log 6 | stderr_logfile=/tmp/isucon.php.log 7 | autostart=false 8 | -------------------------------------------------------------------------------- /provisioning/all-in-one/files/supervisor.python.conf: -------------------------------------------------------------------------------- 1 | [program:python] 2 | directory=/home/isucon/webapp/python 3 | command=/home/isucon/env.sh gunicorn -w 4 -b 127.0.0.1:8080 app:app 4 | user=isucon 5 | stdout_logfile=/tmp/isucon.python.log 6 | stderr_logfile=/tmp/isucon.python.log 7 | autostart=false 8 | -------------------------------------------------------------------------------- /provisioning/all-in-one/files/supervisor.ruby.conf: -------------------------------------------------------------------------------- 1 | [program:ruby] 2 | directory=/home/isucon/webapp/ruby 3 | command=/home/isucon/env.sh bundle exec unicorn -c ./unicorn_config.rb 4 | user=isucon 5 | stdout_logfile=/tmp/isucon.ruby.log 6 | stderr_logfile=/tmp/isucon.ruby.log 7 | # turn this to false for other languages 8 | autostart=true 9 | -------------------------------------------------------------------------------- /provisioning/all-in-one/files/supervisor.scala.conf: -------------------------------------------------------------------------------- 1 | [program:scala] 2 | directory=/home/isucon/webapp/scala 3 | command=/home/isucon/env.sh ./target/launcher 4 | user=isucon 5 | stdout_logfile=/tmp/isucon.scala.log 6 | stderr_logfile=/tmp/isucon.scala.log 7 | autostart=false 8 | -------------------------------------------------------------------------------- /provisioning/all-in-one/files/supervisor.search-name.conf: -------------------------------------------------------------------------------- 1 | [program:search-name] 2 | directory=/home/isucon/isucon5-final/api/search-name 3 | command=/home/isucon/env.sh ./gradlew run 4 | user=isucon 5 | stdout_logfile=/tmp/api.search-name.log 6 | stderr_logfile=/tmp/api.search-name.log 7 | autostart=true 8 | -------------------------------------------------------------------------------- /provisioning/all-in-one/files/supervisor.tenki.conf: -------------------------------------------------------------------------------- 1 | [program:tenki] 2 | directory=/home/isucon/isucon5-final/api/go/tenki 3 | command=/home/isucon/env.sh ./tenki -v=0 -p=8988 -w=500 -i=3000 4 | user=isucon 5 | stdout_logfile=/tmp/api.tenki.log 6 | stderr_logfile=/tmp/api.tenki.log 7 | autostart=true 8 | -------------------------------------------------------------------------------- /provisioning/all-in-one/keys/root_id_rsa: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEogIBAAKCAQEAsLbbKRq/uxS89H+nfwn3dqOTM0NdftPw3uyodm5uly37uzNn 3 | EZNyi/BbryfGvGYAGwfz4lBA0Wql6NlFOeIMyWDppSCzO8rvCf1NoiayAytDD3Od 4 | 8SyR85Pj8wUalr1bFtj8LCKspFe7IEVYCB3OMDe/jmc3Yk3SnucJ31sWLOI8eOjA 5 | MZH7/NX5NhR3pKn+D/3WVCCQbUtVIgo8PDtnLmhh1pDB2C1HqNfD0d8kEfcylv+X 6 | MYWF0wKzUbUAcEy10LUAofxA2IxsJxKrPymPlbLOPd96RE9h6YZ8xtpt9rdGAkOB 7 | KW/bAMMQdGqsTdyDw9JC7VaczIDhxtacl3YUOQIDAQABAoIBAEuZXrb+B4o8e/3J 8 | Ytm5ZNGvdvjWV/g7KW/lJMjNw6gPdwMGIZDmWHm/kSmkxaOxq1flFhP6q1Ar5OBx 9 | mukBaOD6Adqv25232n2WjRDSpxMt/dltZ+NWYvYmjb1YsKBOT9q9Z1xmVR9VnOtY 10 | XynRvnToVJ3SUGJQ0stCIfoY2KrIRFj2lJ5svALj1Z1NiQeQaAEMf7YAiOrLbNUo 11 | 1vBDMYBC1Dv0+38GgupoXO3buyYBsz/C7qpsmF9ouLo96+gqva9fkkizXVnzbDdT 12 | j5To9Wp+dYzDl6QTCiGpyuYgHclBxpRpdbyLICdmhXw8R077XV1cSzmnJYNsZiFg 13 | BjWBPUUCgYEA3hDMl7+du7h3CGSkW0xtBAIdzsNRWYRzr/QQ/KLo5PZcYqzgLblO 14 | vkApQPB8+JCToHxaqH6Ihy0sJRQyj2HxRmnOdBvloXZjV0owIVgMpjEYbEtBK2rN 15 | 0G1uKfDnsS9smiN8B4R215XtpCtqssv93Jh8Htf7isTRDpEp+DNS4V8CgYEAy7fp 16 | 7Je+RAz3dPLT70PasmaV1b5VVAr6sU8fE49nsbs+g0vmnp70uaEd1wTEtZoW0KCl 17 | Zz/wGpjcxb8m1xUuW5iiN5rdN4I4gtFv21YFDMn3EaGZfgy7l7SdhLfOq+3Dgn80 18 | 87bFFtxxI/sLGaCGWJCXSKcZGVRXMk8Vfq0Y+WcCgYAvZ1qlUiwztG8EhadoLepf 19 | nqwKRTuKZnHjr7AongYlSknyboD0gchDaKLlz/B9hy9cZO9dZJV0dbokuCkK3peI 20 | tnFx67qbOxB9w8J+e7NHjtdt1qq0v/nrclC/90MeWcdPKCAD4s0TvFecYgBG5rDs 21 | dEiatPRnbRhLicVxzFL29QKBgGK8nPBDC8DH2BgiqX3KEXFuLykNuyWkvKS7iIBe 22 | fQ+zhTT10K0ItexSnrfcY8rxCCXN9tz4LFN3y2k8oIKWjYVvkRAKSzXgM6uT/vb7 23 | 1i7ApLMy88YYPcPlkoME43KJJr1VEkEdUKEn7t5Viqe9GeBLFEfuVUfljO2hTvW6 24 | x+P5AoGAJA1yv2yaRgWLX94nfSQoV6o9gyz55IjwqfMhD4wL6WNbHYU6OqixEGpv 25 | KRPsUnVkDJflqKFZQ/SCF3/ciu1Kx+Q/geqpZ7c+tco7u7X+iNBXv6KQBJLRkVEA 26 | fA6lHC4PiD8/bQbUTKgKlVLuY2RGJ1veEJwjVP0g7NxIxAEP/H4= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /provisioning/api/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'thor' 4 | -------------------------------------------------------------------------------- /provisioning/api/ansible/00_devel.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: api 3 | gather_facts: no 4 | tasks: 5 | - apt: name=python-selinux state=present update_cache=true 6 | - service: name=apparmor enabled=no state=stopped 7 | - apt: name=git state=present 8 | - apt: name=gcc state=present 9 | - apt: name=patch state=present 10 | - apt: name=autoconf state=present 11 | - apt: name=automake state=present 12 | - apt: name=bison state=present 13 | - apt: name=build-essential 14 | - apt: name=libssl-dev state=present 15 | - apt: name=libyaml-dev state=present 16 | - apt: name=libreadline6-dev state=present 17 | - apt: name=zlib1g-dev state=present 18 | - apt: name=libncurses5-dev state=present 19 | - apt: name=libffi-dev state=present 20 | - apt: name=libgdbm3 state=present 21 | - apt: name=libgdbm-dev state=present 22 | - apt: name=libmysqlclient-dev state=present 23 | - apt: name=libcurl4-openssl-dev state=present 24 | - apt: name=libjpeg-turbo8 state=present 25 | - apt: name=libjpeg-turbo8-dev state=present 26 | - apt: name=libpng12-0 state=present 27 | - apt: name=libpng12-dev state=present 28 | - apt: name=libmcrypt4 state=present 29 | - apt: name=libmcrypt-dev state=present 30 | - apt: name=libtidy-0.99-0 state=present 31 | - apt: name=libtidy-dev state=present 32 | - apt: name=libxml2-dev state=present 33 | - apt: name=libxslt1-dev state=present 34 | - apt: name=readline-common state=present 35 | - apt: name=re2c state=present 36 | # for node-install 37 | - apt: name=curl state=present 38 | # for php --with-openssl 39 | - apt: name=pkg-config 40 | -------------------------------------------------------------------------------- /provisioning/api/ansible/01_isucon_base.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: api 3 | gather_facts: no 4 | tasks: 5 | - name: change timezone to JST 6 | shell: cp -p /usr/share/zoneinfo/Japan /etc/localtime 7 | - group: name=wheel 8 | - user: name=isucon groups=wheel 9 | - copy: src=../files/bashrc dest=/home/isucon/.bashrc owner=isucon mode=755 10 | - lineinfile: dest=/etc/sudoers state=present regexp='^%wheel ALL\=' line='%wheel ALL=(ALL) NOPASSWD:ALL' validate='visudo -cf %s' 11 | -------------------------------------------------------------------------------- /provisioning/api/ansible/02_xbuild.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: api 3 | sudo: yes 4 | sudo_user: isucon 5 | gather_facts: no 6 | tasks: 7 | - git: 8 | repo=https://github.com/tagomoris/xbuild.git 9 | dest=/home/isucon/.xbuild 10 | update=yes 11 | # ruby 12 | - command: /home/isucon/.xbuild/ruby-install 2.2.3 /home/isucon/.local/ruby 13 | args: 14 | creates: /home/isucon/.local/ruby/bin/ruby 15 | # node 16 | - command: /home/isucon/.xbuild/node-install v4.1.1 /home/isucon/.local/node 17 | args: 18 | creates: /home/isucon/.local/node/bin/node 19 | # python3 20 | - command: /home/isucon/.xbuild/python-install 3.4.3 /home/isucon/.local/python3 21 | args: 22 | creates: /home/isucon/.local/python3/bin/python 23 | # perl 24 | - command: /home/isucon/.xbuild/perl-install 5.20.2 /home/isucon/.local/perl 25 | args: 26 | creates: /home/isucon/.local/perl/bin/perl 27 | # php 28 | - command: /home/isucon/.xbuild/php-install 5.6.13 /home/isucon/.local/php -- --with-pear --with-openssl 29 | args: 30 | creates: /home/isucon/.local/php/bin/php 31 | - copy: src=../files/php.ini dest=/home/isucon/.local/php/etc/php.ini owner=isucon mode=644 32 | # golang 33 | - command: /home/isucon/.xbuild/go-install 1.5 /home/isucon/.local/go 34 | args: 35 | creates: /home/isucon/.local/go/bin/go 36 | # scala 37 | - shell: curl http://downloads.typesafe.com/scala/2.11.7/scala-2.11.7.tgz | (cd /home/isucon/.local && tar xzf -) 38 | args: 39 | creates: /home/isucon/.local/scala-2.11.7/bin/scala 40 | - file: src=/home/isucon/.local/scala-2.11.7 dest=/home/isucon/.local/scala state=link 41 | 42 | - hosts: api 43 | gather_facts: no 44 | tasks: 45 | - apt_repository: repo='ppa:webupd8team/java' 46 | - name: Autoaccept license for Java8 47 | debconf: name='oracle-java8-installer' question='shared/accepted-oracle-license-v1-1' value='true' vtype='select' 48 | - apt: name=oracle-java8-installer update_cache=yes 49 | - apt: name=ca-certificates 50 | - apt: name=oracle-java8-set-default 51 | - apt_repository: repo='ppa:cwchien/gradle' 52 | - apt: name=gradle-2.8 update_cache=yes 53 | - file: src=/usr/lib/jvm/java-8-oracle dest=/usr/lib/jvm/default-java owner=root state=link 54 | -------------------------------------------------------------------------------- /provisioning/api/ansible/03_middleware.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: api 3 | gather_facts: no 4 | tasks: 5 | - apt: name=nginx state=present 6 | - service: name=nginx state=running enabled=true 7 | - copy: src=../files/nginx.conf dest=/etc/nginx/nginx.conf owner=root mode=644 8 | notify: 9 | - reload nginx 10 | # - apt: name=mysql-server-5.6 state=present 11 | # - file: path=/var/run/mysqld state=directory owner=mysql mode=775 12 | # - name: copy my.cnf 13 | # copy: src=../files/my.cnf dest=/etc/mysqld/my.cnf owner=root mode=644 14 | # notify: 15 | # - restart mysqld 16 | # - service: name=mysql state=running enabled=true 17 | # - apt: name=python-mysqldb state=present 18 | # - mysql_user: name=isucon password=isucon priv=*.*:ALL state=present 19 | handlers: 20 | # - name: restart mysqld 21 | # action: service name=mysql state=restarted 22 | - name: reload nginx 23 | action: service name=nginx state=restarted 24 | -------------------------------------------------------------------------------- /provisioning/api/ansible/05_api_servers.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: api 3 | gather_facts: no 4 | sudo: yes 5 | sudo_user: isucon 6 | tasks: 7 | - file: path=/home/isucon/.ssh state=directory owner=isucon mode=755 8 | - copy: src=../keys/deploy_id_rsa dest=/home/isucon/.ssh/deploy_id_rsa owner=isucon mode=600 9 | - git: 10 | repo=git@github.com:tagomoris/isucon5-final.git 11 | dest=/home/isucon/isucon5-final 12 | key_file=/home/isucon/.ssh/deploy_id_rsa 13 | accept_hostkey=yes 14 | - copy: src=../files/env.sh dest=/home/isucon/env.sh owner=isucon mode=755 15 | 16 | - name: KEN_ALL API 17 | shell: PATH=/home/isucon/.local/ruby/bin:$PATH bundle install 18 | args: 19 | chdir: /home/isucon/isucon5-final/api/ken 20 | 21 | - name: PerfectSequrity API 22 | shell: PATH=/home/isucon/.local/node/bin:$PATH npm install 23 | args: 24 | chdir: /home/isucon/isucon5-final/api/perfect_security 25 | 26 | - name: Search Name API 27 | shell: gradle wrapper 28 | args: 29 | chdir: /home/isucon/isucon5-final/api/search-name 30 | 31 | - name: Tenki API 32 | shell: PATH=/home/isucon/.local/go/bin:$PATH GOROOT=/home/isucon/.local/go GOPATH=/home/isucon/isucon5-final/api/go go build 33 | args: 34 | chdir: /home/isucon/isucon5-final/api/go/tenki 35 | 36 | - hosts: api 37 | gather_facts: no 38 | tasks: 39 | - apt: name=supervisor state=present 40 | # In ubuntu default /etc/supervisor/supervisord.conf 41 | # [include] 42 | # files = /etc/supervisor/conf.d/*.conf 43 | - copy: src=../files/supervisor.ken.conf dest=/etc/supervisor/conf.d/ken.conf 44 | - supervisorctl: name=ken state=present 45 | - supervisorctl: name=ken state=restarted 46 | 47 | - copy: src=../files/supervisor.perfect_security.conf dest=/etc/supervisor/conf.d/perfect_security.conf 48 | - supervisorctl: name=perfect_security state=present 49 | - supervisorctl: name=perfect_security state=restarted 50 | 51 | - copy: src=../files/supervisor.search-name.conf dest=/etc/supervisor/conf.d/search-name.conf 52 | - supervisorctl: name=search-name state=present 53 | - supervisorctl: name=search-name state=restarted 54 | 55 | - copy: src=../files/supervisor.tenki.conf dest=/etc/supervisor/conf.d/tenki.conf 56 | - supervisorctl: name=tenki state=present 57 | - supervisorctl: name=tenki state=restarted 58 | -------------------------------------------------------------------------------- /provisioning/api/ansible/_cleanup.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: no 4 | tasks: 5 | - shell: rm -rf /tmp/*; true 6 | ### Should be done in image/ 7 | # - lineinfile: dest=/root/.ssh/authorized_keys regexp=root@base-image state=absent 8 | # - remove: root .ansible, .bash_history ... 9 | # - file: path=/root/.ansible state=absent 10 | # - file: path=/root/.bash_history state=absent 11 | # - file: path=/root/.viminfo state=absent 12 | # - file: path=/home/isucon/.bash_history state=absent 13 | # - file: path=/home/isucon/.viminfo state=absent 14 | - file: path=/home/{{ lookup('env', 'USER') }} state=absent 15 | -------------------------------------------------------------------------------- /provisioning/api/files/bashrc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ -f /etc/bashrc ]; then 3 | . /etc/bashrc 4 | fi 5 | 6 | export PATH=/usr/local/bin:$PATH 7 | export PATH=/home/isucon/.local/ruby/bin:$PATH 8 | export PATH=/home/isucon/.local/node/bin:$PATH 9 | export PATH=/home/isucon/.local/python3/bin:$PATH 10 | export PATH=/home/isucon/.local/perl/bin:$PATH 11 | export PATH=/home/isucon/.local/php/bin:$PATH 12 | export PATH=/home/isucon/.local/php/sbin:$PATH 13 | export PATH=/home/isucon/.local/go/bin:$PATH 14 | export GOROOT=/home/isucon/.local/go 15 | export GOPATH=/home/isucon/webapp/go 16 | export PATH=/home/isucon/.local/scala/bin:$PATH 17 | -------------------------------------------------------------------------------- /provisioning/api/files/env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | export PATH=/usr/local/bin:/home/isucon/.local/ruby/bin:/home/isucon/.local/node/bin:/home/isucon/.local/python3/bin:/home/isucon/.local/perl/bin:/home/isucon/.local/php/bin:/home/isucon/.local/php/sbin:/home/isucon/.local/go/bin:/home/isucon/.local/scala/bin:$PATH 3 | export GOPATH=/home/isucon/gocode 4 | 5 | exec $* 6 | -------------------------------------------------------------------------------- /provisioning/api/files/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | 3 | events { 4 | worker_connections 1024; 5 | } 6 | 7 | http { 8 | upstream app { 9 | server 127.0.0.1:8080; 10 | } 11 | 12 | server { 13 | location / { 14 | proxy_set_header Host $host; 15 | proxy_pass http://app; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /provisioning/api/files/supervisor.ken.conf: -------------------------------------------------------------------------------- 1 | [program:ken] 2 | directory=/home/isucon/isucon5-final/api/ken 3 | command=/home/isucon/env.sh bundle exec unicorn -c ./unicorn_config.rb 4 | user=isucon 5 | stdout_logfile=/tmp/api.ken.log 6 | stderr_logfile=/tmp/api.ken.log 7 | autostart=true 8 | -------------------------------------------------------------------------------- /provisioning/api/files/supervisor.perfect_security.conf: -------------------------------------------------------------------------------- 1 | [program:perfect_security] 2 | directory=/home/isucon/isucon5-final/api/perfect_security 3 | command=/home/isucon/env.sh node index.js 4 | user=isucon 5 | stdout_logfile=/tmp/api.perfect_security.log 6 | stderr_logfile=/tmp/api.perfect_security.log 7 | autostart=true 8 | -------------------------------------------------------------------------------- /provisioning/api/files/supervisor.search-name.conf: -------------------------------------------------------------------------------- 1 | [program:search-name] 2 | directory=/home/isucon/isucon5-final/api/search-name 3 | command=/home/isucon/env.sh ./gradlew run 4 | user=isucon 5 | stdout_logfile=/tmp/api.search-name.log 6 | stderr_logfile=/tmp/api.search-name.log 7 | autostart=true 8 | -------------------------------------------------------------------------------- /provisioning/api/files/supervisor.tenki.conf: -------------------------------------------------------------------------------- 1 | [program:tenki] 2 | directory=/home/isucon/isucon5-final/api/go/tenki 3 | command=/home/isucon/env.sh ./tenki -v=0 -p=8988 -w=500 -i=3000 4 | user=isucon 5 | stdout_logfile=/tmp/api.tenki.log 6 | stderr_logfile=/tmp/api.tenki.log 7 | autostart=true 8 | -------------------------------------------------------------------------------- /provisioning/api/keys/deploy_id_rsa: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEA0E+4Qh+tmTYZ5fux+GYn9Me7jYmF2lXJX6JLRztMLbMPjJEW 3 | J7kBsPB7yQ1EpF9jVEwGAseEWS9u13wujKrAQeQrICktMRJtCo2yO5Vvo7Pn4IPO 4 | EA4MTjclb1nKE0Ge1bxZQiFfCDuhKEivRG7kPPnXGBVr2kRIa1qK3grYcgEsYrix 5 | AG73ocTrqLi0T63k0hTSFQpU+jfHx0X2HjePhf3EUWPDxQleErZvnfXYFnWykSlg 6 | L9YeSg+f1/qVrMr3N5DjCnUo1fTwuXgWsW8Ef/M1m5m4f2yh85STCV9m/klpfkBS 7 | 3wRa01nqVoe0gJPowja6d2a1AiyXXUh7vQZCfQIDAQABAoIBAHZs++nLrJuvoCWZ 8 | Y+I94XVNn5ilmE05/BO8ZmOGmJZad/qH+Tp3+TgoX5c7TczM1eF0nu4xk1JInxEu 9 | biBWapqLJuFPx3tgaFFZoPwyxpcgjjCbfiiuc9x7iXK2byVnZu9H9s6bvjUmAUav 10 | m8Sh7muj9d6hPwGFVE6D2PLG46pbbPt/NhRtcV+jBAtUYzOWk1CEpP8wG5WAyJJW 11 | O/uZDYKONnpkho6S/K7t30nPOnVGdoqwR70hGEyOGgjaTqz7QyI1Ghm2ea8/2QRr 12 | 2oM+jqGkl/2bx+nwX+tgEnbT2+jkZSvHHa3l/KCCC+AxiR8MtZ+ZYxC7Ai1QaSAv 13 | A2c46BkCgYEA+mvjTAqjFDOHJQIZr1l0ojcNkBixKllBBHqF2s0rtR+ezwouC7l2 14 | itek0s68s442nFBDhI86bDzedWRxwm1Ec3ph+z2YvIs4RZCyoRKmbnmau5Bj5jWb 15 | rzK5BG2o/ji1stUfJTLMnwleIgZsK6IwJu7PWGqz33pS1UpOQRYxoecCgYEA1POv 16 | cRxOClcxeqQzGYUg4Cn8n/DoSMgLLtnSBis1GVrQ2EdCBnac/E5i4Z4wKtYaNGG/ 17 | 2DWtA653MOrQFK3DqnCuB95WQAfios1hhWb7zaoybXfsxazTUBdA9eMWGoUD0giX 18 | 6cQ2q/t2wdM13no5rKk1ey7VTnxUrWpxxhOYs/sCgYAJQyRNE7ekb6N4AvPgQHbH 19 | 6TFfOwqSfmqhN8brqNsM//ZnwgCh/mIcEI3QHkVsfr4WWgGlTYbjqfywat6qSlBV 20 | 1Rj6qfSURLH4ILn6qy3suCK4/UY0pZb0i/O77jJp9L8Dtk5ImfBnkXkh2Qr3MjCF 21 | wB97LbcpdOTLbswmLCP50QKBgGVUo4oOLvBqtyellI8zMwaX1BcDWnSvg+rCSVcY 22 | Hkc3WKNhnQBYVrEUV6cGT+NCR+vfC5vFRtO2pA7J3UPJv46N2bHy0VXcqrJPSnVh 23 | ILanoyFF7IvPhinZNtcKPM1XuA6seiUJcf56RPNMHpkDzgfj6If6LBQRw3VVblgT 24 | oRkbAoGBAIjg4NyfWNt9AWc+cHqTpm7+JlMQcvQ2IWgOuajXAKV7ZxcRsJMD/dLO 25 | QkAIgA/plie7IkmRIeSBT1C05pm4+28XViRsybUEIs+/YXc7XTd6s/lHVJwLoXg7 26 | We9ovtyHuZT/3UI58g4fFvUbI6xBBd7QiafOrugY+BO7+qOwK9My 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /provisioning/api/keys/root_id_rsa: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEogIBAAKCAQEAsLbbKRq/uxS89H+nfwn3dqOTM0NdftPw3uyodm5uly37uzNn 3 | EZNyi/BbryfGvGYAGwfz4lBA0Wql6NlFOeIMyWDppSCzO8rvCf1NoiayAytDD3Od 4 | 8SyR85Pj8wUalr1bFtj8LCKspFe7IEVYCB3OMDe/jmc3Yk3SnucJ31sWLOI8eOjA 5 | MZH7/NX5NhR3pKn+D/3WVCCQbUtVIgo8PDtnLmhh1pDB2C1HqNfD0d8kEfcylv+X 6 | MYWF0wKzUbUAcEy10LUAofxA2IxsJxKrPymPlbLOPd96RE9h6YZ8xtpt9rdGAkOB 7 | KW/bAMMQdGqsTdyDw9JC7VaczIDhxtacl3YUOQIDAQABAoIBAEuZXrb+B4o8e/3J 8 | Ytm5ZNGvdvjWV/g7KW/lJMjNw6gPdwMGIZDmWHm/kSmkxaOxq1flFhP6q1Ar5OBx 9 | mukBaOD6Adqv25232n2WjRDSpxMt/dltZ+NWYvYmjb1YsKBOT9q9Z1xmVR9VnOtY 10 | XynRvnToVJ3SUGJQ0stCIfoY2KrIRFj2lJ5svALj1Z1NiQeQaAEMf7YAiOrLbNUo 11 | 1vBDMYBC1Dv0+38GgupoXO3buyYBsz/C7qpsmF9ouLo96+gqva9fkkizXVnzbDdT 12 | j5To9Wp+dYzDl6QTCiGpyuYgHclBxpRpdbyLICdmhXw8R077XV1cSzmnJYNsZiFg 13 | BjWBPUUCgYEA3hDMl7+du7h3CGSkW0xtBAIdzsNRWYRzr/QQ/KLo5PZcYqzgLblO 14 | vkApQPB8+JCToHxaqH6Ihy0sJRQyj2HxRmnOdBvloXZjV0owIVgMpjEYbEtBK2rN 15 | 0G1uKfDnsS9smiN8B4R215XtpCtqssv93Jh8Htf7isTRDpEp+DNS4V8CgYEAy7fp 16 | 7Je+RAz3dPLT70PasmaV1b5VVAr6sU8fE49nsbs+g0vmnp70uaEd1wTEtZoW0KCl 17 | Zz/wGpjcxb8m1xUuW5iiN5rdN4I4gtFv21YFDMn3EaGZfgy7l7SdhLfOq+3Dgn80 18 | 87bFFtxxI/sLGaCGWJCXSKcZGVRXMk8Vfq0Y+WcCgYAvZ1qlUiwztG8EhadoLepf 19 | nqwKRTuKZnHjr7AongYlSknyboD0gchDaKLlz/B9hy9cZO9dZJV0dbokuCkK3peI 20 | tnFx67qbOxB9w8J+e7NHjtdt1qq0v/nrclC/90MeWcdPKCAD4s0TvFecYgBG5rDs 21 | dEiatPRnbRhLicVxzFL29QKBgGK8nPBDC8DH2BgiqX3KEXFuLykNuyWkvKS7iIBe 22 | fQ+zhTT10K0ItexSnrfcY8rxCCXN9tz4LFN3y2k8oIKWjYVvkRAKSzXgM6uT/vb7 23 | 1i7ApLMy88YYPcPlkoME43KJJr1VEkEdUKEn7t5Viqe9GeBLFEfuVUfljO2hTvW6 24 | x+P5AoGAJA1yv2yaRgWLX94nfSQoV6o9gyz55IjwqfMhD4wL6WNbHYU6OqixEGpv 25 | KRPsUnVkDJflqKFZQ/SCF3/ciu1Kx+Q/geqpZ7c+tco7u7X+iNBXv6KQBJLRkVEA 26 | fA6lHC4PiD8/bQbUTKgKlVLuY2RGJ1veEJwjVP0g7NxIxAEP/H4= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /provisioning/api/keys/root_id_rsa.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCwttspGr+7FLz0f6d/Cfd2o5MzQ11+0/De7Kh2bm6XLfu7M2cRk3KL8FuvJ8a8ZgAbB/PiUEDRaqXo2UU54gzJYOmlILM7yu8J/U2iJrIDK0MPc53xLJHzk+PzBRqWvVsW2PwsIqykV7sgRVgIHc4wN7+OZzdiTdKe5wnfWxYs4jx46MAxkfv81fk2FHekqf4P/dZUIJBtS1UiCjw8O2cuaGHWkMHYLUeo18PR3yQR9zKW/5cxhYXTArNRtQBwTLXQtQCh/EDYjGwnEqs/KY+Vss4933pET2HphnzG2m32t0YCQ4Epb9sAwxB0aqxN3IPD0kLtVpzMgOHG1pyXdhQ5 root@base-image.isucon.net 2 | -------------------------------------------------------------------------------- /provisioning/bench/.gitignore: -------------------------------------------------------------------------------- 1 | tmp/ 2 | *~ 3 | -------------------------------------------------------------------------------- /provisioning/bench/ansible/00_devel.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: bench 3 | gather_facts: no 4 | tasks: 5 | - apt: name=python-selinux state=present update_cache=true 6 | - service: name=apparmor enabled=no state=stopped 7 | - apt: name=git state=present 8 | - apt: name=gcc state=present 9 | - apt: name=patch state=present 10 | - apt: name=autoconf state=present 11 | - apt: name=automake state=present 12 | - apt: name=bison state=present 13 | - apt: name=build-essential 14 | - apt: name=libssl-dev state=present 15 | - apt: name=libyaml-dev state=present 16 | - apt: name=libreadline6-dev state=present 17 | - apt: name=zlib1g-dev state=present 18 | - apt: name=libncurses5-dev state=present 19 | - apt: name=libffi-dev state=present 20 | - apt: name=libgdbm3 state=present 21 | - apt: name=libgdbm-dev state=present 22 | - apt: name=libmysqlclient-dev state=present 23 | - apt: name=libcurl4-openssl-dev state=present 24 | - apt: name=libjpeg-turbo8 state=present 25 | - apt: name=libjpeg-turbo8-dev state=present 26 | - apt: name=libpng12-0 state=present 27 | - apt: name=libpng12-dev state=present 28 | - apt: name=libmcrypt4 state=present 29 | - apt: name=libmcrypt-dev state=present 30 | - apt: name=libtidy-0.99-0 state=present 31 | - apt: name=libtidy-dev state=present 32 | - apt: name=libxml2-dev state=present 33 | - apt: name=libxslt1-dev state=present 34 | - apt: name=readline-common state=present 35 | - apt: name=re2c state=present 36 | # for node-install 37 | - apt: name=curl state=present 38 | # for php --with-openssl 39 | - apt: name=pkg-config 40 | -------------------------------------------------------------------------------- /provisioning/bench/ansible/01_isucon_base.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: bench 3 | gather_facts: no 4 | tasks: 5 | - name: change timezone to JST 6 | shell: cp -p /usr/share/zoneinfo/Japan /etc/localtime 7 | - group: name=wheel 8 | - user: name=isucon groups=wheel 9 | - copy: src=../files/bashrc dest=/home/isucon/.bashrc owner=isucon mode=755 10 | - lineinfile: dest=/etc/sudoers state=present regexp='^%wheel ALL\=' line='%wheel ALL=(ALL) NOPASSWD:ALL' validate='visudo -cf %s' 11 | -------------------------------------------------------------------------------- /provisioning/bench/ansible/02_xbuild_part.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: bench 3 | sudo: yes 4 | sudo_user: isucon 5 | gather_facts: no 6 | tasks: 7 | - git: 8 | repo=https://github.com/tagomoris/xbuild.git 9 | dest=/home/isucon/.xbuild 10 | update=yes 11 | # ruby 12 | - command: /home/isucon/.xbuild/ruby-install 2.2.3 /home/isucon/.local/ruby 13 | args: 14 | creates: /home/isucon/.local/ruby/bin/ruby 15 | 16 | - hosts: bench 17 | gather_facts: no 18 | tasks: 19 | - apt_repository: repo='ppa:webupd8team/java' 20 | - name: Autoaccept license for Java8 21 | debconf: name='oracle-java8-installer' question='shared/accepted-oracle-license-v1-1' value='true' vtype='select' 22 | - apt: name=oracle-java8-installer update_cache=yes 23 | - apt: name=ca-certificates 24 | - apt: name=oracle-java8-set-default 25 | - apt_repository: repo='ppa:cwchien/gradle' 26 | - apt: name=gradle-2.8 update_cache=yes 27 | - file: src=/usr/lib/jvm/java-8-oracle dest=/usr/lib/jvm/default-java owner=root state=link 28 | -------------------------------------------------------------------------------- /provisioning/bench/ansible/06_deploy_bench_tool.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: bench 3 | gather_facts: no 4 | sudo: yes 5 | sudo_user: isucon 6 | tasks: 7 | - file: path=/home/isucon/.ssh state=directory owner=isucon mode=755 8 | - copy: src=../keys/deploy_id_rsa dest=/home/isucon/.ssh/deploy_id_rsa owner=isucon mode=600 9 | - git: 10 | repo=git@github.com:tagomoris/isucon5-final.git 11 | dest=/home/isucon/isucon5-final 12 | key_file=/home/isucon/.ssh/deploy_id_rsa 13 | accept_hostkey=yes 14 | - copy: src=../files/env.sh dest=/home/isucon/env.sh owner=isucon mode=755 15 | - name: ruby 16 | shell: PATH=/home/isucon/.local/ruby/bin:$PATH bundle install 17 | args: 18 | chdir: /home/isucon/isucon5-final/bench 19 | - name: java build 20 | shell: gradle compileJava 21 | args: 22 | chdir: /home/isucon/isucon5-final/bench 23 | 24 | - hosts: bench 25 | gather_facts: no 26 | tasks: 27 | - apt: name=supervisor state=present 28 | - name: ruby agent 1 29 | copy: src=../files/supervisor.agent1.conf dest=/etc/supervisor/conf.d/agent1.conf owner=root mode=644 30 | - supervisorctl: name=agent1 state=present 31 | - supervisorctl: name=agent1 state=restarted 32 | - name: ruby agent 2 33 | copy: src=../files/supervisor.agent2.conf dest=/etc/supervisor/conf.d/agent2.conf owner=root mode=644 34 | - supervisorctl: name=agent2 state=present 35 | - supervisorctl: name=agent2 state=restarted 36 | -------------------------------------------------------------------------------- /provisioning/bench/files/bashrc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ -f /etc/bashrc ]; then 3 | . /etc/bashrc 4 | fi 5 | 6 | export PATH=/usr/local/bin:$PATH 7 | export PATH=/home/isucon/.local/ruby/bin:$PATH 8 | -------------------------------------------------------------------------------- /provisioning/bench/files/env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | export PATH=/home/isucon/.local/ruby/bin:/usr/local/bin:/usr/local/bin:/usr/bin:/bin 3 | export LANG=ja_JP.UTF-8 4 | export RACK_ENV=production 5 | export _JAVA_OPTIONS="-Dfile.encoding=UTF8 -Duser.timezone=JST" 6 | export JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF8 7 | 8 | exec $* 9 | -------------------------------------------------------------------------------- /provisioning/bench/files/supervisor.agent1.conf: -------------------------------------------------------------------------------- 1 | [program:agent1] 2 | directory=/home/isucon/isucon5-final/bench 3 | command=/home/isucon/env.sh bundle exec ruby ./agent.rb 4 | user=isucon 5 | environment=ISUCON_BENCH_DATADIR="/home/isucon/isucon5-final/bench/json" 6 | stdout_logfile=/tmp/agent1.log 7 | stderr_logfile=/tmp/agent1.log 8 | # turn this to false for other languages 9 | autostart=true 10 | -------------------------------------------------------------------------------- /provisioning/bench/files/supervisor.agent2.conf: -------------------------------------------------------------------------------- 1 | [program:agent2] 2 | directory=/home/isucon/isucon5-final/bench 3 | command=/home/isucon/env.sh bundle exec ruby ./agent.rb 4 | user=isucon 5 | environment=ISUCON_BENCH_DATADIR="/home/isucon/isucon5-final/bench/json" 6 | stdout_logfile=/tmp/agent2.log 7 | stderr_logfile=/tmp/agent2.log 8 | # turn this to false for other languages 9 | autostart=true 10 | -------------------------------------------------------------------------------- /provisioning/bench/keys/deploy_id_rsa: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEA0E+4Qh+tmTYZ5fux+GYn9Me7jYmF2lXJX6JLRztMLbMPjJEW 3 | J7kBsPB7yQ1EpF9jVEwGAseEWS9u13wujKrAQeQrICktMRJtCo2yO5Vvo7Pn4IPO 4 | EA4MTjclb1nKE0Ge1bxZQiFfCDuhKEivRG7kPPnXGBVr2kRIa1qK3grYcgEsYrix 5 | AG73ocTrqLi0T63k0hTSFQpU+jfHx0X2HjePhf3EUWPDxQleErZvnfXYFnWykSlg 6 | L9YeSg+f1/qVrMr3N5DjCnUo1fTwuXgWsW8Ef/M1m5m4f2yh85STCV9m/klpfkBS 7 | 3wRa01nqVoe0gJPowja6d2a1AiyXXUh7vQZCfQIDAQABAoIBAHZs++nLrJuvoCWZ 8 | Y+I94XVNn5ilmE05/BO8ZmOGmJZad/qH+Tp3+TgoX5c7TczM1eF0nu4xk1JInxEu 9 | biBWapqLJuFPx3tgaFFZoPwyxpcgjjCbfiiuc9x7iXK2byVnZu9H9s6bvjUmAUav 10 | m8Sh7muj9d6hPwGFVE6D2PLG46pbbPt/NhRtcV+jBAtUYzOWk1CEpP8wG5WAyJJW 11 | O/uZDYKONnpkho6S/K7t30nPOnVGdoqwR70hGEyOGgjaTqz7QyI1Ghm2ea8/2QRr 12 | 2oM+jqGkl/2bx+nwX+tgEnbT2+jkZSvHHa3l/KCCC+AxiR8MtZ+ZYxC7Ai1QaSAv 13 | A2c46BkCgYEA+mvjTAqjFDOHJQIZr1l0ojcNkBixKllBBHqF2s0rtR+ezwouC7l2 14 | itek0s68s442nFBDhI86bDzedWRxwm1Ec3ph+z2YvIs4RZCyoRKmbnmau5Bj5jWb 15 | rzK5BG2o/ji1stUfJTLMnwleIgZsK6IwJu7PWGqz33pS1UpOQRYxoecCgYEA1POv 16 | cRxOClcxeqQzGYUg4Cn8n/DoSMgLLtnSBis1GVrQ2EdCBnac/E5i4Z4wKtYaNGG/ 17 | 2DWtA653MOrQFK3DqnCuB95WQAfios1hhWb7zaoybXfsxazTUBdA9eMWGoUD0giX 18 | 6cQ2q/t2wdM13no5rKk1ey7VTnxUrWpxxhOYs/sCgYAJQyRNE7ekb6N4AvPgQHbH 19 | 6TFfOwqSfmqhN8brqNsM//ZnwgCh/mIcEI3QHkVsfr4WWgGlTYbjqfywat6qSlBV 20 | 1Rj6qfSURLH4ILn6qy3suCK4/UY0pZb0i/O77jJp9L8Dtk5ImfBnkXkh2Qr3MjCF 21 | wB97LbcpdOTLbswmLCP50QKBgGVUo4oOLvBqtyellI8zMwaX1BcDWnSvg+rCSVcY 22 | Hkc3WKNhnQBYVrEUV6cGT+NCR+vfC5vFRtO2pA7J3UPJv46N2bHy0VXcqrJPSnVh 23 | ILanoyFF7IvPhinZNtcKPM1XuA6seiUJcf56RPNMHpkDzgfj6If6LBQRw3VVblgT 24 | oRkbAoGBAIjg4NyfWNt9AWc+cHqTpm7+JlMQcvQ2IWgOuajXAKV7ZxcRsJMD/dLO 25 | QkAIgA/plie7IkmRIeSBT1C05pm4+28XViRsybUEIs+/YXc7XTd6s/lHVJwLoXg7 26 | We9ovtyHuZT/3UI58g4fFvUbI6xBBd7QiafOrugY+BO7+qOwK9My 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /provisioning/eventapp/ansible/00_devel.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: manage 3 | gather_facts: no 4 | tasks: 5 | - apt: name=python-selinux state=present update_cache=true 6 | - service: name=apparmor enabled=no state=stopped 7 | - apt: name=git state=present 8 | - apt: name=gcc state=present 9 | - apt: name=patch state=present 10 | - apt: name=autoconf state=present 11 | - apt: name=automake state=present 12 | - apt: name=bison state=present 13 | - apt: name=build-essential 14 | - apt: name=libssl-dev state=present 15 | - apt: name=libyaml-dev state=present 16 | - apt: name=libreadline6-dev state=present 17 | - apt: name=zlib1g-dev state=present 18 | - apt: name=libncurses5-dev state=present 19 | - apt: name=libffi-dev state=present 20 | - apt: name=libgdbm3 state=present 21 | - apt: name=libgdbm-dev state=present 22 | - apt: name=libmysqlclient-dev state=present 23 | - apt: name=libcurl4-openssl-dev state=present 24 | - apt: name=libjpeg-turbo8 state=present 25 | - apt: name=libjpeg-turbo8-dev state=present 26 | - apt: name=libpng12-0 state=present 27 | - apt: name=libpng12-dev state=present 28 | - apt: name=libmcrypt4 state=present 29 | - apt: name=libmcrypt-dev state=present 30 | - apt: name=libtidy-0.99-0 state=present 31 | - apt: name=libtidy-dev state=present 32 | - apt: name=libxml2-dev state=present 33 | - apt: name=libxslt1-dev state=present 34 | - apt: name=readline-common state=present 35 | - apt: name=re2c state=present 36 | # for node.js 37 | - apt: name=curl 38 | # for php --with-openssl 39 | - apt: name=pkg-config 40 | -------------------------------------------------------------------------------- /provisioning/eventapp/ansible/01_isucon_base.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: manage 3 | gather_facts: no 4 | tasks: 5 | - name: change timezone to JST 6 | shell: cp -p /usr/share/zoneinfo/Japan /etc/localtime 7 | - group: name=wheel 8 | - user: name=isucon groups=wheel 9 | - copy: src=../files/bashrc dest=/home/isucon/.bashrc owner=isucon mode=755 10 | - lineinfile: dest=/etc/sudoers state=present regexp='^%wheel ALL\=' line='%wheel ALL=(ALL) NOPASSWD:ALL' validate='visudo -cf %s' 11 | -------------------------------------------------------------------------------- /provisioning/eventapp/ansible/02_xbuild_part.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: manage 3 | sudo: yes 4 | sudo_user: isucon 5 | gather_facts: no 6 | tasks: 7 | - git: 8 | repo=https://github.com/tagomoris/xbuild.git 9 | dest=/home/isucon/.xbuild 10 | update=yes 11 | # ruby 12 | - command: /home/isucon/.xbuild/ruby-install 2.2.3 /home/isucon/.local/ruby 13 | args: 14 | creates: /home/isucon/.local/ruby/bin/ruby 15 | 16 | - hosts: manage 17 | gather_facts: no 18 | tasks: 19 | - apt_repository: repo='ppa:webupd8team/java' 20 | - name: Autoaccept license for Java8 21 | debconf: name='oracle-java8-installer' question='shared/accepted-oracle-license-v1-1' value='true' vtype='select' 22 | - apt: name=oracle-java8-installer update_cache=yes 23 | - apt: name=ca-certificates 24 | - apt: name=oracle-java8-set-default 25 | - apt_repository: repo='ppa:cwchien/gradle' 26 | - apt: name=gradle-2.8 update_cache=yes 27 | - file: src=/usr/lib/jvm/java-8-oracle dest=/usr/lib/jvm/default-java owner=root state=link 28 | -------------------------------------------------------------------------------- /provisioning/eventapp/ansible/03_middleware.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: manage 3 | gather_facts: no 4 | tasks: 5 | - apt: name=nginx state=present 6 | - service: name=nginx state=running enabled=true 7 | - copy: src=../files/nginx.conf dest=/etc/nginx/nginx.conf owner=root mode=644 8 | notify: 9 | - reload nginx 10 | - apt: name=mysql-server-5.6 state=present 11 | - file: path=/var/run/mysqld state=directory owner=mysql mode=775 12 | - lineinfile: dest=/etc/mysql/my.cnf regexp='^#?.*bind-address.*=.*127.0.0.1' line='bind-address = 0.0.0.0' 13 | notify: 14 | - restart mysqld 15 | - service: name=mysql state=running enabled=true 16 | - apt: name=python-mysqldb state=present 17 | # - mysql_user: name=portaltony password=kamipo-awesome login_host="%" priv=*.*:ALL state=present 18 | # うまくいかない……手でやった 19 | handlers: 20 | - name: restart mysqld 21 | action: service name=mysql state=restarted 22 | - name: reload nginx 23 | action: service name=nginx state=restarted 24 | -------------------------------------------------------------------------------- /provisioning/eventapp/ansible/07_deploy_event_app.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: manage 3 | gather_facts: no 4 | sudo: yes 5 | sudo_user: isucon 6 | tasks: 7 | - file: path=/home/isucon/.ssh state=directory owner=isucon mode=755 8 | - copy: src=../keys/deploy_id_rsa dest=/home/isucon/.ssh/deploy_id_rsa owner=isucon mode=600 9 | - git: 10 | repo=git@github.com:tagomoris/isucon5-final.git 11 | dest=/home/isucon/isucon5-final 12 | key_file=/home/isucon/.ssh/deploy_id_rsa 13 | accept_hostkey=yes 14 | - name: ruby 15 | shell: PATH=/home/isucon/.local/ruby/bin:$PATH bundle install 16 | args: 17 | chdir: /home/isucon/isucon5-final/eventapp 18 | 19 | - hosts: manage 20 | gather_facts: no 21 | tasks: 22 | - copy: src=../files/env.eventapp.sh dest=/home/isucon/env.sh owner=isucon mode=755 23 | - apt: name=supervisor state=present 24 | - name: ruby eventapp unicorn 25 | copy: src=../files/supervisor.eventapp.conf dest=/etc/supervisor/conf.d/eventapp.conf owner=root mode=644 26 | - supervisorctl: name=eventapp state=present 27 | - supervisorctl: name=eventapp state=restarted 28 | -------------------------------------------------------------------------------- /provisioning/eventapp/files/bashrc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ -f /etc/bashrc ]; then 3 | . /etc/bashrc 4 | fi 5 | 6 | export PATH=/usr/local/bin:$PATH 7 | export PATH=/home/isucon/.local/ruby/bin:$PATH 8 | -------------------------------------------------------------------------------- /provisioning/eventapp/files/env.eventapp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | export PATH=/home/isucon/.local/ruby/bin:/usr/local/bin:/usr/local/bin:/usr/bin:/bin 3 | export LANG=ja_JP.UTF-8 4 | export RACK_ENV=production 5 | 6 | exec $* 7 | -------------------------------------------------------------------------------- /provisioning/eventapp/files/my.cnf: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | datadir=/var/lib/mysql 3 | socket=/var/lib/mysql/mysql.sock 4 | symbolic-links=0 5 | 6 | max_allowed_packet=300M 7 | 8 | [mysqld_safe] 9 | log-error=/var/log/mysql/mysqld.log 10 | pid-file=/var/run/mysqld/mysqld.pid 11 | -------------------------------------------------------------------------------- /provisioning/eventapp/files/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 4; 2 | 3 | worker_rlimit_nofile 4096; 4 | 5 | events { 6 | worker_connections 24; 7 | } 8 | 9 | http { 10 | upstream app { 11 | server 127.0.0.1:8080; 12 | } 13 | 14 | server { 15 | include mime.types; 16 | 17 | location /css { 18 | root /home/isucon/isucon5-final/eventapp/public; 19 | } 20 | location /fonts { 21 | root /home/isucon/isucon5-final/eventapp/public; 22 | } 23 | location /js { 24 | root /home/isucon/isucon5-final/eventapp/public; 25 | } 26 | location / { 27 | proxy_set_header Host $host; 28 | proxy_pass http://app; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /provisioning/eventapp/files/supervisor.eventapp.conf: -------------------------------------------------------------------------------- 1 | [program:eventapp] 2 | directory=/home/isucon/isucon5-final/eventapp 3 | command=/home/isucon/env.sh bundle exec foreman start 4 | user=isucon 5 | stdout_logfile=/tmp/eventapp.log 6 | stderr_logfile=/tmp/eventapp.log 7 | # turn this to false for other languages 8 | autostart=true 9 | -------------------------------------------------------------------------------- /provisioning/eventapp/keys/deploy_id_rsa: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEA0E+4Qh+tmTYZ5fux+GYn9Me7jYmF2lXJX6JLRztMLbMPjJEW 3 | J7kBsPB7yQ1EpF9jVEwGAseEWS9u13wujKrAQeQrICktMRJtCo2yO5Vvo7Pn4IPO 4 | EA4MTjclb1nKE0Ge1bxZQiFfCDuhKEivRG7kPPnXGBVr2kRIa1qK3grYcgEsYrix 5 | AG73ocTrqLi0T63k0hTSFQpU+jfHx0X2HjePhf3EUWPDxQleErZvnfXYFnWykSlg 6 | L9YeSg+f1/qVrMr3N5DjCnUo1fTwuXgWsW8Ef/M1m5m4f2yh85STCV9m/klpfkBS 7 | 3wRa01nqVoe0gJPowja6d2a1AiyXXUh7vQZCfQIDAQABAoIBAHZs++nLrJuvoCWZ 8 | Y+I94XVNn5ilmE05/BO8ZmOGmJZad/qH+Tp3+TgoX5c7TczM1eF0nu4xk1JInxEu 9 | biBWapqLJuFPx3tgaFFZoPwyxpcgjjCbfiiuc9x7iXK2byVnZu9H9s6bvjUmAUav 10 | m8Sh7muj9d6hPwGFVE6D2PLG46pbbPt/NhRtcV+jBAtUYzOWk1CEpP8wG5WAyJJW 11 | O/uZDYKONnpkho6S/K7t30nPOnVGdoqwR70hGEyOGgjaTqz7QyI1Ghm2ea8/2QRr 12 | 2oM+jqGkl/2bx+nwX+tgEnbT2+jkZSvHHa3l/KCCC+AxiR8MtZ+ZYxC7Ai1QaSAv 13 | A2c46BkCgYEA+mvjTAqjFDOHJQIZr1l0ojcNkBixKllBBHqF2s0rtR+ezwouC7l2 14 | itek0s68s442nFBDhI86bDzedWRxwm1Ec3ph+z2YvIs4RZCyoRKmbnmau5Bj5jWb 15 | rzK5BG2o/ji1stUfJTLMnwleIgZsK6IwJu7PWGqz33pS1UpOQRYxoecCgYEA1POv 16 | cRxOClcxeqQzGYUg4Cn8n/DoSMgLLtnSBis1GVrQ2EdCBnac/E5i4Z4wKtYaNGG/ 17 | 2DWtA653MOrQFK3DqnCuB95WQAfios1hhWb7zaoybXfsxazTUBdA9eMWGoUD0giX 18 | 6cQ2q/t2wdM13no5rKk1ey7VTnxUrWpxxhOYs/sCgYAJQyRNE7ekb6N4AvPgQHbH 19 | 6TFfOwqSfmqhN8brqNsM//ZnwgCh/mIcEI3QHkVsfr4WWgGlTYbjqfywat6qSlBV 20 | 1Rj6qfSURLH4ILn6qy3suCK4/UY0pZb0i/O77jJp9L8Dtk5ImfBnkXkh2Qr3MjCF 21 | wB97LbcpdOTLbswmLCP50QKBgGVUo4oOLvBqtyellI8zMwaX1BcDWnSvg+rCSVcY 22 | Hkc3WKNhnQBYVrEUV6cGT+NCR+vfC5vFRtO2pA7J3UPJv46N2bHy0VXcqrJPSnVh 23 | ILanoyFF7IvPhinZNtcKPM1XuA6seiUJcf56RPNMHpkDzgfj6If6LBQRw3VVblgT 24 | oRkbAoGBAIjg4NyfWNt9AWc+cHqTpm7+JlMQcvQ2IWgOuajXAKV7ZxcRsJMD/dLO 25 | QkAIgA/plie7IkmRIeSBT1C05pm4+28XViRsybUEIs+/YXc7XTd6s/lHVJwLoXg7 26 | We9ovtyHuZT/3UI58g4fFvUbI6xBBd7QiafOrugY+BO7+qOwK9My 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /provisioning/image/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'thor' 4 | -------------------------------------------------------------------------------- /provisioning/image/ansible/00_devel.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: guests:extras 3 | #- hosts: extras 4 | gather_facts: no 5 | tasks: 6 | - copy: src=../files/sources.list dest=/etc/apt/sources.list owner=root mode=644 7 | - apt: name=python-selinux state=present update_cache=true 8 | - service: name=apparmor enabled=no state=stopped 9 | - apt: name=git state=present 10 | - apt: name=gcc state=present 11 | - apt: name=patch state=present 12 | - apt: name=autoconf state=present 13 | - apt: name=automake state=present 14 | - apt: name=bison state=present 15 | - apt: name=build-essential 16 | - apt: name=libssl-dev state=present 17 | - apt: name=libyaml-dev state=present 18 | - apt: name=libreadline6-dev state=present 19 | - apt: name=zlib1g-dev state=present 20 | - apt: name=libncurses5-dev state=present 21 | - apt: name=libffi-dev state=present 22 | - apt: name=libgdbm3 state=present 23 | - apt: name=libgdbm-dev state=present 24 | - apt: name=libmysqlclient-dev state=present 25 | - apt: name=libpq-dev state=present 26 | - apt: name=libcurl4-openssl-dev state=present 27 | - apt: name=libjpeg-turbo8 state=present 28 | - apt: name=libjpeg-turbo8-dev state=present 29 | - apt: name=libpng12-0 state=present 30 | - apt: name=libpng12-dev state=present 31 | - apt: name=libmcrypt4 state=present 32 | - apt: name=libmcrypt-dev state=present 33 | - apt: name=libtidy-0.99-0 state=present 34 | - apt: name=libtidy-dev state=present 35 | - apt: name=libxml2-dev state=present 36 | - apt: name=libxslt1-dev state=present 37 | - apt: name=readline-common state=present 38 | - apt: name=re2c state=present 39 | # for node-install 40 | - apt: name=curl state=present 41 | # for php --with-openssl 42 | - apt: name=pkg-config 43 | -------------------------------------------------------------------------------- /provisioning/image/ansible/01_isucon_base.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: guests:extras 3 | #- hosts: extras 4 | gather_facts: no 5 | tasks: 6 | - name: change timezone to JST 7 | shell: cp -p /usr/share/zoneinfo/Japan /etc/localtime 8 | - group: name=wheel 9 | - user: name=isucon groups=wheel 10 | - copy: src=../files/bashrc dest=/home/isucon/.bashrc owner=isucon mode=755 11 | - lineinfile: dest=/etc/sudoers state=present regexp='^%wheel ALL\=' line='%wheel ALL=(ALL) NOPASSWD:ALL' validate='visudo -cf %s' 12 | -------------------------------------------------------------------------------- /provisioning/image/ansible/02_xbuild.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: guests:extras 3 | #- hosts: extras 4 | sudo: yes 5 | sudo_user: isucon 6 | gather_facts: no 7 | tasks: 8 | - git: 9 | repo=https://github.com/tagomoris/xbuild.git 10 | dest=/home/isucon/.xbuild 11 | update=yes 12 | # ruby 13 | - command: /home/isucon/.xbuild/ruby-install 2.2.3 /home/isucon/.local/ruby 14 | args: 15 | creates: /home/isucon/.local/ruby/bin/ruby 16 | # node 17 | - command: /home/isucon/.xbuild/node-install v4.1.1 /home/isucon/.local/node 18 | args: 19 | creates: /home/isucon/.local/node/bin/node 20 | # python3 21 | - command: /home/isucon/.xbuild/python-install 3.4.3 /home/isucon/.local/python3 22 | args: 23 | creates: /home/isucon/.local/python3/bin/python 24 | # perl 25 | - command: /home/isucon/.xbuild/perl-install 5.20.2 /home/isucon/.local/perl 26 | args: 27 | creates: /home/isucon/.local/perl/bin/perl 28 | # php 29 | - command: /home/isucon/.xbuild/php-install 5.6.13 /home/isucon/.local/php -- --with-pear --with-openssl --with-pdo-pgsql 30 | args: 31 | creates: /home/isucon/.local/php/bin/php 32 | - copy: src=../files/php.ini dest=/home/isucon/.local/php/etc/php.ini owner=isucon mode=644 33 | # golang 34 | - command: /home/isucon/.xbuild/go-install 1.5 /home/isucon/.local/go 35 | args: 36 | creates: /home/isucon/.local/go/bin/go 37 | # scala 38 | - shell: curl http://downloads.typesafe.com/scala/2.11.7/scala-2.11.7.tgz | (cd /home/isucon/.local && tar xzf -) 39 | args: 40 | creates: /home/isucon/.local/scala-2.11.7/bin/scala 41 | - file: src=/home/isucon/.local/scala-2.11.7 dest=/home/isucon/.local/scala state=link 42 | 43 | - hosts: guests:extras 44 | #- hosts: extras 45 | gather_facts: no 46 | tasks: 47 | - apt_repository: repo='ppa:webupd8team/java' 48 | - name: Autoaccept license for Java8 49 | debconf: name='oracle-java8-installer' question='shared/accepted-oracle-license-v1-1' value='true' vtype='select' 50 | - apt: name=oracle-java8-installer update_cache=yes 51 | - apt: name=ca-certificates 52 | - apt: name=oracle-java8-set-default 53 | - apt_repository: repo='ppa:cwchien/gradle' 54 | - apt: name=gradle-2.8 update_cache=yes 55 | - file: src=/usr/lib/jvm/java-8-oracle dest=/usr/lib/jvm/default-java owner=root state=link 56 | -------------------------------------------------------------------------------- /provisioning/image/ansible/03_middleware.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: guests:extras 3 | #- hosts: extras 4 | gather_facts: no 5 | tasks: 6 | - apt: name=nginx state=present 7 | - service: name=nginx state=running enabled=true 8 | - copy: src=../files/nginx.conf dest=/etc/nginx/nginx.conf owner=root mode=644 9 | notify: 10 | - reload nginx 11 | - copy: src=../files/nginx.php.conf dest=/etc/nginx/nginx.php.conf owner=root mode=644 12 | - apt: name=python-psycopg2 state=present 13 | - apt_key: url=https://www.postgresql.org/media/keys/ACCC4CF8.asc state=present 14 | - apt_repository: repo='deb http://apt.postgresql.org/pub/repos/apt/ trusty-pgdg main' state=present update_cache=yes 15 | - apt: name=postgresql-9.4 state=present 16 | - apt: name=postgresql-contrib-9.4 state=present 17 | - apt: name=postgresql-client-9.4 state=present 18 | - name: copy postgresql configurations 19 | copy: src=../files/postgresql.conf dest=/etc/postgresql/9.4/main/postgresql.conf owner=postgres group=postgres mode=644 20 | notify: 21 | - restart postgresql 22 | - name: copy postgres connection controls 23 | copy: src=../files/pg_hba.conf dest=/etc/postgresql/9.4/main/pg_hba.conf owner=postgres group=postgres mode=640 24 | notify: 25 | - restart postgresql 26 | - service: name=postgresql state=running enabled=true 27 | handlers: 28 | - name: restart postgresql 29 | action: service name=postgresql state=restarted 30 | - name: reload nginx 31 | action: service name=nginx state=restarted 32 | 33 | - hosts: guests:extras 34 | #- hosts: extras 35 | gather_facts: no 36 | sudo: yes 37 | sudo_user: postgres 38 | tasks: 39 | - postgresql_user: name=isucon 40 | - postgresql_db: name=isucon5f owner=isucon encoding=utf8 template=template0 41 | - postgresql_ext: name=pgcrypto db=isucon5f 42 | 43 | - hosts: guests:extras 44 | #- hosts: extras 45 | gather_facts: no 46 | sudo: yes 47 | sudo_user: isucon 48 | tasks: 49 | - copy: src=../files/schema.sql dest=/tmp/schema.sql 50 | - shell: cat /tmp/schema.sql | psql isucon5f 51 | - command: rm /tmp/schema.sql 52 | -------------------------------------------------------------------------------- /provisioning/image/ansible/_cleanup.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: guests:extras 3 | gather_facts: no 4 | tasks: 5 | - shell: rm -rf /tmp/*; true 6 | - file: state=absent path=/home/isucon/.ssh/deploy_id_rsa 7 | - file: path=/root/.ansible state=absent 8 | - file: path=/root/.bash_history state=absent 9 | - file: path=/root/.viminfo state=absent 10 | - file: path=/home/isucon/.bash_history state=absent 11 | - file: path=/home/isucon/.viminfo state=absent 12 | -------------------------------------------------------------------------------- /provisioning/image/files/bashrc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ -f /etc/bashrc ]; then 3 | . /etc/bashrc 4 | fi 5 | 6 | export PATH=/usr/local/bin:$PATH 7 | export PATH=/home/isucon/.local/ruby/bin:$PATH 8 | export PATH=/home/isucon/.local/node/bin:$PATH 9 | export PATH=/home/isucon/.local/python3/bin:$PATH 10 | export PATH=/home/isucon/.local/perl/bin:$PATH 11 | export PATH=/home/isucon/.local/php/bin:$PATH 12 | export PATH=/home/isucon/.local/php/sbin:$PATH 13 | export PATH=/home/isucon/.local/go/bin:$PATH 14 | export GOROOT=/home/isucon/.local/go 15 | export GOPATH=/home/isucon/webapp/go 16 | export PATH=/home/isucon/.local/scala/bin:$PATH 17 | -------------------------------------------------------------------------------- /provisioning/image/files/env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | export PATH=/usr/local/bin:/home/isucon/.local/ruby/bin:/home/isucon/.local/node/bin:/home/isucon/.local/python3/bin:/home/isucon/.local/perl/bin:/home/isucon/.local/php/bin:/home/isucon/.local/php/sbin:/home/isucon/.local/go/bin:/home/isucon/.local/scala/bin:$PATH 3 | export GOPATH=/home/isucon/gocode 4 | export _JAVA_OPTIONS="-Dfile.encoding=UTF-8" 5 | 6 | exec $* 7 | -------------------------------------------------------------------------------- /provisioning/image/files/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | 3 | events { 4 | worker_connections 1024; 5 | } 6 | 7 | http { 8 | upstream app { 9 | server 127.0.0.1:8080; 10 | } 11 | 12 | server { 13 | location / { 14 | proxy_set_header Host $host; 15 | proxy_pass http://app; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /provisioning/image/files/nginx.php.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | 3 | events { 4 | worker_connections 1024; 5 | } 6 | 7 | http { 8 | include /etc/nginx/mime.types; 9 | types_hash_max_size 2048; 10 | 11 | upstream php-fpm { 12 | server 127.0.0.1:8080; 13 | } 14 | 15 | server { 16 | location ~ ^/(css|fonts|js) { 17 | root /home/isucon/webapp/static; 18 | } 19 | 20 | location / { 21 | root /home/isucon/webapp/php; 22 | 23 | fastcgi_pass php-fpm; 24 | fastcgi_index index.php; 25 | fastcgi_read_timeout 120; 26 | 27 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 28 | fastcgi_param QUERY_STRING $query_string; 29 | fastcgi_param REQUEST_METHOD $request_method; 30 | fastcgi_param CONTENT_TYPE $content_type; 31 | fastcgi_param CONTENT_LENGTH $content_length; 32 | 33 | fastcgi_param SCRIPT_NAME $fastcgi_script_name; 34 | fastcgi_param REQUEST_URI $request_uri; 35 | fastcgi_param DOCUMENT_URI $document_uri; 36 | fastcgi_param DOCUMENT_ROOT $document_root; 37 | fastcgi_param SERVER_PROTOCOL $server_protocol; 38 | fastcgi_param HTTPS $https if_not_empty; 39 | 40 | fastcgi_param GATEWAY_INTERFACE CGI/1.1; 41 | fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; 42 | 43 | fastcgi_param REMOTE_ADDR $http_x_forwarded_for; 44 | fastcgi_param REMOTE_PORT $remote_port; 45 | fastcgi_param SERVER_ADDR $server_addr; 46 | fastcgi_param SERVER_PORT $server_port; 47 | fastcgi_param SERVER_NAME $server_name; 48 | 49 | fastcgi_param REDIRECT_STATUS 200; 50 | 51 | rewrite ^(.*)$ /index.php?$1 break; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /provisioning/image/files/pg_hba.conf: -------------------------------------------------------------------------------- 1 | local all postgres peer 2 | local all all peer 3 | host all all 127.0.0.1/32 trust 4 | host all all ::1/128 trust 5 | -------------------------------------------------------------------------------- /provisioning/image/files/schema.sql: -------------------------------------------------------------------------------- 1 | -- CREATE USER isucon; 2 | -- CREATE DATABASE isucon5f OWNER isucon ENCODING 'utf8'; 3 | 4 | -- \connect isucon5f 5 | 6 | CREATE TYPE grades AS ENUM ('micro', 'small', 'standard', 'premium'); 7 | 8 | CREATE TABLE users ( 9 | id SERIAL PRIMARY KEY, 10 | email VARCHAR(256) NOT NULL, 11 | salt VARCHAR(32) NOT NULL, 12 | passhash bytea NOT NULL, 13 | grade grades 14 | ); 15 | 16 | -- CREATE EXTENSION pgcrypto; 17 | 18 | CREATE TYPE token_types AS ENUM ('header', 'param'); 19 | 20 | CREATE TABLE endpoints ( 21 | service VARCHAR(32) NOT NULL PRIMARY KEY, 22 | meth VARCHAR(16) NOT NULL, 23 | token_type token_types, 24 | token_key VARCHAR(64), 25 | uri TEXT 26 | ); 27 | 28 | CREATE TABLE subscriptions ( 29 | user_id INTEGER REFERENCES users (id) NOT NULL PRIMARY KEY, 30 | arg TEXT 31 | ); 32 | -------------------------------------------------------------------------------- /provisioning/image/files/supervisor.golang.conf: -------------------------------------------------------------------------------- 1 | [program:golang] 2 | directory=/home/isucon/webapp/golang 3 | command=/home/isucon/env.sh ./app 4 | user=isucon 5 | stdout_logfile=/tmp/isucon.golang.log 6 | stderr_logfile=/tmp/isucon.golang.log 7 | autostart=false 8 | -------------------------------------------------------------------------------- /provisioning/image/files/supervisor.java.conf: -------------------------------------------------------------------------------- 1 | [program:java] 2 | directory=/home/isucon/webapp/java 3 | command=/home/isucon/env.sh java -Djava.security.egd=file:/dev/./urandom -jar target/isucon5f-0.0.1-SNAPSHOT.jar --server.port=8080 4 | user=isucon 5 | stdout_logfile=/tmp/isucon.java.log 6 | stderr_logfile=/tmp/isucon.java.log 7 | autostart=false 8 | -------------------------------------------------------------------------------- /provisioning/image/files/supervisor.node.conf: -------------------------------------------------------------------------------- 1 | [program:node] 2 | directory=/home/isucon/webapp/node 3 | command=/home/isucon/env.sh node app.js 4 | user=isucon 5 | stdout_logfile=/tmp/isucon.node.log 6 | stderr_logfile=/tmp/isucon.node.log 7 | autostart=false 8 | -------------------------------------------------------------------------------- /provisioning/image/files/supervisor.perl.conf: -------------------------------------------------------------------------------- 1 | [program:perl] 2 | directory=/home/isucon/webapp/perl 3 | command=/home/isucon/env.sh carton exec -- plackup -s Starman -p 8080 --workers 4 --disable-keepalive app.psgi 4 | user=isucon 5 | stdout_logfile=/tmp/isucon.perl.log 6 | stderr_logfile=/tmp/isucon.perl.log 7 | autostart=false 8 | -------------------------------------------------------------------------------- /provisioning/image/files/supervisor.php.conf: -------------------------------------------------------------------------------- 1 | [program:php] 2 | directory=/home/isucon/webapp/php 3 | command=/home/isucon/env.sh php-fpm -y php-fpm.conf 4 | user=isucon 5 | stdout_logfile=/tmp/isucon.php.log 6 | stderr_logfile=/tmp/isucon.php.log 7 | autostart=false 8 | -------------------------------------------------------------------------------- /provisioning/image/files/supervisor.python.conf: -------------------------------------------------------------------------------- 1 | [program:python] 2 | directory=/home/isucon/webapp/python 3 | command=/home/isucon/env.sh gunicorn -w 4 -b 127.0.0.1:8080 app:app 4 | user=isucon 5 | stdout_logfile=/tmp/isucon.python.log 6 | stderr_logfile=/tmp/isucon.python.log 7 | autostart=false 8 | -------------------------------------------------------------------------------- /provisioning/image/files/supervisor.ruby.conf: -------------------------------------------------------------------------------- 1 | [program:ruby] 2 | directory=/home/isucon/webapp/ruby 3 | command=/home/isucon/env.sh bundle exec unicorn -c ./unicorn_config.rb 4 | user=isucon 5 | stdout_logfile=/tmp/isucon.ruby.log 6 | stderr_logfile=/tmp/isucon.ruby.log 7 | # turn this to false for other languages 8 | autostart=true 9 | -------------------------------------------------------------------------------- /provisioning/image/files/supervisor.scala.conf: -------------------------------------------------------------------------------- 1 | [program:scala] 2 | directory=/home/isucon/webapp/scala 3 | command=/home/isucon/env.sh ./target/launcher 4 | user=isucon 5 | stdout_logfile=/tmp/isucon.scala.log 6 | stderr_logfile=/tmp/isucon.scala.log 7 | autostart=false 8 | -------------------------------------------------------------------------------- /provisioning/image/keys/deploy_id_rsa: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEA0E+4Qh+tmTYZ5fux+GYn9Me7jYmF2lXJX6JLRztMLbMPjJEW 3 | J7kBsPB7yQ1EpF9jVEwGAseEWS9u13wujKrAQeQrICktMRJtCo2yO5Vvo7Pn4IPO 4 | EA4MTjclb1nKE0Ge1bxZQiFfCDuhKEivRG7kPPnXGBVr2kRIa1qK3grYcgEsYrix 5 | AG73ocTrqLi0T63k0hTSFQpU+jfHx0X2HjePhf3EUWPDxQleErZvnfXYFnWykSlg 6 | L9YeSg+f1/qVrMr3N5DjCnUo1fTwuXgWsW8Ef/M1m5m4f2yh85STCV9m/klpfkBS 7 | 3wRa01nqVoe0gJPowja6d2a1AiyXXUh7vQZCfQIDAQABAoIBAHZs++nLrJuvoCWZ 8 | Y+I94XVNn5ilmE05/BO8ZmOGmJZad/qH+Tp3+TgoX5c7TczM1eF0nu4xk1JInxEu 9 | biBWapqLJuFPx3tgaFFZoPwyxpcgjjCbfiiuc9x7iXK2byVnZu9H9s6bvjUmAUav 10 | m8Sh7muj9d6hPwGFVE6D2PLG46pbbPt/NhRtcV+jBAtUYzOWk1CEpP8wG5WAyJJW 11 | O/uZDYKONnpkho6S/K7t30nPOnVGdoqwR70hGEyOGgjaTqz7QyI1Ghm2ea8/2QRr 12 | 2oM+jqGkl/2bx+nwX+tgEnbT2+jkZSvHHa3l/KCCC+AxiR8MtZ+ZYxC7Ai1QaSAv 13 | A2c46BkCgYEA+mvjTAqjFDOHJQIZr1l0ojcNkBixKllBBHqF2s0rtR+ezwouC7l2 14 | itek0s68s442nFBDhI86bDzedWRxwm1Ec3ph+z2YvIs4RZCyoRKmbnmau5Bj5jWb 15 | rzK5BG2o/ji1stUfJTLMnwleIgZsK6IwJu7PWGqz33pS1UpOQRYxoecCgYEA1POv 16 | cRxOClcxeqQzGYUg4Cn8n/DoSMgLLtnSBis1GVrQ2EdCBnac/E5i4Z4wKtYaNGG/ 17 | 2DWtA653MOrQFK3DqnCuB95WQAfios1hhWb7zaoybXfsxazTUBdA9eMWGoUD0giX 18 | 6cQ2q/t2wdM13no5rKk1ey7VTnxUrWpxxhOYs/sCgYAJQyRNE7ekb6N4AvPgQHbH 19 | 6TFfOwqSfmqhN8brqNsM//ZnwgCh/mIcEI3QHkVsfr4WWgGlTYbjqfywat6qSlBV 20 | 1Rj6qfSURLH4ILn6qy3suCK4/UY0pZb0i/O77jJp9L8Dtk5ImfBnkXkh2Qr3MjCF 21 | wB97LbcpdOTLbswmLCP50QKBgGVUo4oOLvBqtyellI8zMwaX1BcDWnSvg+rCSVcY 22 | Hkc3WKNhnQBYVrEUV6cGT+NCR+vfC5vFRtO2pA7J3UPJv46N2bHy0VXcqrJPSnVh 23 | ILanoyFF7IvPhinZNtcKPM1XuA6seiUJcf56RPNMHpkDzgfj6If6LBQRw3VVblgT 24 | oRkbAoGBAIjg4NyfWNt9AWc+cHqTpm7+JlMQcvQ2IWgOuajXAKV7ZxcRsJMD/dLO 25 | QkAIgA/plie7IkmRIeSBT1C05pm4+28XViRsybUEIs+/YXc7XTd6s/lHVJwLoXg7 26 | We9ovtyHuZT/3UI58g4fFvUbI6xBBd7QiafOrugY+BO7+qOwK9My 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /provisioning/inventory.ini: -------------------------------------------------------------------------------- 1 | [manage] 2 | isu-adm01.data-hotel.net 3 | 4 | [api] 5 | isu-bm[18:20].data-hotel.net 6 | 7 | [bench] 8 | isu-adm[03:05].data-hotel.net 9 | 10 | [guests] 11 | isu[01:04][a:c] api_host=203.104.208.158 12 | isu[05:08][a:c] api_host=203.104.208.159 13 | isu[09:12][a:c] api_host=203.104.208.160 14 | 15 | isu[13:16][a:c] api_host=203.104.208.158 16 | isu[17:20][a:c] api_host=203.104.208.159 17 | isu[21:25][a:c] api_host=203.104.208.160 18 | 19 | [extras] 20 | isu[26:28][a:c] api_host=203.104.208.160 21 | -------------------------------------------------------------------------------- /webapp/golang/.hold: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isucon/isucon5-final/981f7721e94e655280d71f70f64fa13b94181128/webapp/golang/.hold -------------------------------------------------------------------------------- /webapp/golang/README.md: -------------------------------------------------------------------------------- 1 | ## 前提 2 | - Go がインストールされており、`go` にパスが通っていること 3 | - $GOPATH がセットされていること 4 | 5 | ## 実行 6 | 7 | ``` 8 | go get github.com/tagomoris/isucon5-final 9 | cd $GOPATH/github.com/tagomoris/isucon5-final/webapp/golang 10 | go get 11 | go run app.go 12 | ``` 13 | 14 | -------------------------------------------------------------------------------- /webapp/golang/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AirISU Sign in 10 | 11 | 12 | 13 | 14 | 15 |
16 | 24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /webapp/golang/templates/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AirISU 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | 24 |

AirISU: {{ .User.Email }}

25 |
26 | 27 |
28 |
29 | 30 |
31 |

© ISU Company 2015

32 |
33 | 34 |
35 | 36 | 54 | 55 | 63 | 64 | 65 | 66 | 67 | 68 | 73 | 74 | -------------------------------------------------------------------------------- /webapp/golang/templates/signup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AirISU Signup 10 | 11 | 12 | 13 | 14 | 15 |
16 | 33 |
34 | 35 | 36 | -------------------------------------------------------------------------------- /webapp/golang/templates/user.js: -------------------------------------------------------------------------------- 1 | var AIR_ISU_REFRESH_INTERVAL = {{if eq .Grade "micro" }}{{ 30000 }}{{ else if eq .Grade "small" }}{{ 30000 }}{{ else if eq .Grade "standard" }}{{ 20000 }}{{ else if eq .Grade "premium" }}{{ 10000 }}{{ end }}; -------------------------------------------------------------------------------- /webapp/java/.hold: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isucon/isucon5-final/981f7721e94e655280d71f70f64fa13b94181128/webapp/java/.hold -------------------------------------------------------------------------------- /webapp/java/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isucon/isucon5-final/981f7721e94e655280d71f70f64fa13b94181128/webapp/java/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /webapp/java/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.3/apache-maven-3.3.3-bin.zip -------------------------------------------------------------------------------- /webapp/java/README.md: -------------------------------------------------------------------------------- 1 | ### Build 2 | 3 | ./mvnw clean package -Dmaven.test.skip=true 4 | 5 | ### Run 6 | 7 | java -jar target/isucon5f-0.0.1-SNAPSHOT.jar 8 | 9 | Specifying server port 10 | 11 | java -jar target/isucon5f-0.0.1-SNAPSHOT.jar --server.port=8888 12 | 13 | 14 | 15 | Enabling SQL log (for development) 16 | 17 | java -jar target/isucon5f-0.0.1-SNAPSHOT.jar --spring.profiles.active=sqllog 18 | 19 | ### Option (Memo) 20 | 21 | docker run --rm --name isucon5f -p 5432:5432 -e POSTGRES_PASSWORD= -e POSTGRES_USER=isucon5f -e LC_ALL=C.UTF-8 postgres 22 | 23 | export ISUCON5_DB_HOST=192.168.99.100 24 | export ISUCON5_DB_USER=isucon5f -------------------------------------------------------------------------------- /webapp/java/src/main/java/net/isucon/RestClientConfig.java: -------------------------------------------------------------------------------- 1 | package net.isucon; 2 | 3 | import java.io.IOException; 4 | import java.net.HttpURLConnection; 5 | import java.security.SecureRandom; 6 | import java.security.cert.CertificateException; 7 | import java.security.cert.X509Certificate; 8 | 9 | import javax.net.ssl.*; 10 | 11 | import org.springframework.context.annotation.Bean; 12 | import org.springframework.context.annotation.Configuration; 13 | import org.springframework.http.client.SimpleClientHttpRequestFactory; 14 | import org.springframework.web.client.RestTemplate; 15 | 16 | @Configuration 17 | public class RestClientConfig { 18 | @Bean 19 | RestTemplate restTemplate() throws Exception { 20 | X509TrustManager trustManager = new X509TrustManager() { 21 | @Override 22 | public void checkClientTrusted(X509Certificate[] x509Certificates, 23 | String s) throws CertificateException { 24 | 25 | } 26 | 27 | @Override 28 | public void checkServerTrusted(X509Certificate[] x509Certificates, 29 | String s) throws CertificateException { 30 | 31 | } 32 | 33 | @Override 34 | public X509Certificate[] getAcceptedIssuers() { 35 | return null; 36 | } 37 | }; 38 | SSLContext sslContext = SSLContext.getInstance("SSL"); 39 | sslContext.init(null, new X509TrustManager[] { trustManager }, new SecureRandom()); 40 | 41 | SSLSocketFactory socketFactory = sslContext.getSocketFactory(); 42 | HostnameVerifier verifier = (h, s) -> true; 43 | SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory() { 44 | @Override 45 | protected void prepareConnection(HttpURLConnection connection, 46 | String httpMethod) throws IOException { 47 | if (connection instanceof HttpsURLConnection) { 48 | HttpsURLConnection con = (HttpsURLConnection) connection; 49 | con.setSSLSocketFactory(socketFactory); 50 | con.setHostnameVerifier(verifier); 51 | } 52 | super.prepareConnection(connection, httpMethod); 53 | } 54 | }; 55 | return new RestTemplate(factory); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /webapp/java/src/main/resources/application-sqllog.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.url=jdbc:log4jdbc:postgresql://${ISUCON5_DB_HOST:localhost}:${ISUCON5_DB_PORT:5432}/${ISUCON5_DB_NAME:isucon5f} 2 | spring.datasource.driver-class-name=net.sf.log4jdbc.sql.jdbcapi.DriverSpy 3 | logging.level.jdbc=OFF 4 | logging.level.jdbc.sqltiming=DEBUG 5 | logging.level.jdbc.resultsettable=DEBUG -------------------------------------------------------------------------------- /webapp/java/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.username=${ISUCON5_DB_USER:isucon} 2 | spring.datasource.password=${ISUCON5_DB_PASSWORD:} 3 | spring.datasource.url=jdbc:postgresql://${ISUCON5_DB_HOST:localhost}:${ISUCON5_DB_PORT:5432}/${ISUCON5_DB_NAME:isucon5f} 4 | spring.datasource.sql-script-encoding=UTF-8 5 | spring.datasource.initialize=false 6 | server.tomcat.max-threads=10 7 | -------------------------------------------------------------------------------- /webapp/java/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ${AnsiColor.BRIGHT_RED} ___ ____ _ _ ${AnsiColor.DEFAULT} ____ ___ _ _ 2 | ${AnsiColor.BRIGHT_RED}|_ _/ ___|| | | |${AnsiColor.DEFAULT}/ ___/ _ \| \ | | 3 | ${AnsiColor.BRIGHT_RED} | |\___ \| | | |${AnsiColor.DEFAULT} | | | | | \| | 4 | ${AnsiColor.BRIGHT_RED} | | ___) | |_| |${AnsiColor.DEFAULT} |__| |_| | |\ | 5 | ${AnsiColor.BRIGHT_RED}|___|____/ \___/ ${AnsiColor.DEFAULT}\____\___/|_| \_| 6 | ${AnsiColor.BRIGHT_RED} :: Spring Boot :: ${AnsiColor.DEFAULT} ${spring-boot.formatted-version} -------------------------------------------------------------------------------- /webapp/java/src/main/resources/log4jdbc.log4j2.properties: -------------------------------------------------------------------------------- 1 | log4jdbc.dump.sql.maxlinelength=0 2 | log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator -------------------------------------------------------------------------------- /webapp/java/src/main/resources/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AirISU Signup 10 | 11 | 12 | 13 | 14 |
15 | 26 |
27 | 28 | -------------------------------------------------------------------------------- /webapp/java/src/main/resources/templates/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AirISU Signup 10 | 11 | 12 | 13 | 14 |
15 |
16 | 23 |

AirISU: [[${user.email}]]

24 |
25 | 26 |
27 |
28 | 29 |
30 |

© ISU Company 2015

31 |
32 | 33 |
34 | 35 | 53 | 54 | 62 | 63 | 64 | 65 | 66 | 67 | 72 | 73 | -------------------------------------------------------------------------------- /webapp/java/src/main/resources/templates/signup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AirISU Signup 10 | 11 | 12 | 13 | 14 |
15 | 36 |
37 | 38 | -------------------------------------------------------------------------------- /webapp/java/src/main/resources/templates/userjs.html: -------------------------------------------------------------------------------- 1 | 2 | var AIR_ISU_REFRESH_INTERVAL = /*[[${interval}]]*/ 50000; 3 | -------------------------------------------------------------------------------- /webapp/java/src/test/java/net/isucon/Isucon5fApplicationTests.java: -------------------------------------------------------------------------------- 1 | package net.isucon; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.test.context.web.WebAppConfiguration; 6 | import org.springframework.boot.test.SpringApplicationConfiguration; 7 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 8 | 9 | @RunWith(SpringJUnit4ClassRunner.class) 10 | @SpringApplicationConfiguration(classes = Isucon5fApplication.class) 11 | @WebAppConfiguration 12 | public class Isucon5fApplicationTests { 13 | 14 | @Test 15 | public void contextLoads() { 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /webapp/node/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /webapp/node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "isucon5-final", 3 | "private": true, 4 | "dependencies": { 5 | "async": "1.4.2", 6 | "body-parser": "1.14.1", 7 | "cookie-session": "1.2.0", 8 | "ejs": "2.3.4", 9 | "express": "4.13.3", 10 | "lodash": "3.10.1", 11 | "pg": "4.4.2", 12 | "request": "2.65.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /webapp/node/views/login.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AirISU Sign in 10 | 11 | 12 | 13 | 14 | 15 |
16 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /webapp/node/views/main.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AirISU 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | 24 |

AirISU: <%= user.email %>

25 |
26 | 27 |
28 |
29 | 30 |
31 |

© ISU Company 2015

32 |
33 | 34 |
35 | 36 | 54 | 55 | 63 | 64 | 65 | 66 | 67 | 68 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /webapp/node/views/signup.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AirISU Signup 10 | 11 | 12 | 13 | 14 | 15 |
16 | 33 |
34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /webapp/node/views/userjs.ejs: -------------------------------------------------------------------------------- 1 | <% intervalByGrade = { micro: 30000, small: 30000, standard: 20000, premium: 10000 } %> 2 | var AIR_ISU_REFRESH_INTERVAL = <%= intervalByGrade[grade] %>; 3 | -------------------------------------------------------------------------------- /webapp/perl/.hold: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isucon/isucon5-final/981f7721e94e655280d71f70f64fa13b94181128/webapp/perl/.hold -------------------------------------------------------------------------------- /webapp/perl/README.md: -------------------------------------------------------------------------------- 1 | ### HOT TO RUN ### 2 | 3 | $ carton install 4 | $ carton exec plackup -s Starman -p 8080 -E prod --workers 10 --disable-keepalive app.psgi 5 | 6 | -------------------------------------------------------------------------------- /webapp/perl/app.psgi: -------------------------------------------------------------------------------- 1 | use FindBin; 2 | use lib "$FindBin::Bin/local/lib/perl5"; 3 | use lib "$FindBin::Bin/lib"; 4 | use File::Basename; 5 | use Plack::Builder; 6 | use Isucon5f::Web; 7 | 8 | my $root_dir = File::Basename::dirname(__FILE__); 9 | 10 | my $app = Isucon5f::Web->psgi($root_dir); 11 | builder { 12 | enable 'ReverseProxy'; 13 | enable 'Static', 14 | path => qr!^/(?:(?:css|fonts|js)/|favicon\.ico$)!, 15 | root => File::Basename::dirname($root_dir) . '/static'; 16 | enable 'Session::Cookie', 17 | session_key => "airisu_session", 18 | secret => $ENV{ISUCON5_SESSION_SECRET} || 'tonymoris', 19 | ; 20 | $app; 21 | }; 22 | -------------------------------------------------------------------------------- /webapp/perl/cpanfile: -------------------------------------------------------------------------------- 1 | requires "Kossy", 0.38; 2 | requires "DBIx::Sunny"; 3 | 4 | requires "DBD::Pg"; 5 | requires "Starman"; 6 | requires "Plack::Session"; 7 | requires "Furl"; 8 | requires "IO::Socket::SSL"; 9 | requires "String::Util"; 10 | -------------------------------------------------------------------------------- /webapp/perl/lib/Isucon5f.pm: -------------------------------------------------------------------------------- 1 | package Isucon5f; 2 | 3 | use strict; 4 | use warnings; 5 | use utf8; 6 | 7 | our $VERSION = 0.01; 8 | 9 | 1; 10 | -------------------------------------------------------------------------------- /webapp/perl/t/00_compile.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | use Test::More; 4 | 5 | use_ok $_ for qw( 6 | Isucon5f 7 | Isucon5f::Web 8 | ); 9 | 10 | done_testing; 11 | -------------------------------------------------------------------------------- /webapp/perl/views/login.tx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AirISU Sign in 10 | 11 | 12 | 13 | 14 | 15 |
16 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /webapp/perl/views/main.tx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AirISU 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | 24 |

AirISU: <: $user['email'] :>

25 |
26 | 27 |
28 |
29 | 30 |
31 |

© ISU Company 2015

32 |
33 | 34 |
35 | 36 | 54 | 55 | 63 | 64 | 65 | 66 | 67 | 68 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /webapp/perl/views/signup.tx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AirISU Signup 10 | 11 | 12 | 13 | 14 | 15 |
16 | 33 |
34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /webapp/perl/views/userjs.tx: -------------------------------------------------------------------------------- 1 | : given $grade { 2 | : when 'micro' { 3 | var AIR_ISU_REFRESH_INTERVAL = 30000; 4 | : } 5 | : when 'small' { 6 | var AIR_ISU_REFRESH_INTERVAL = 30000; 7 | : } 8 | : when 'standard' { 9 | var AIR_ISU_REFRESH_INTERVAL = 20000; 10 | : } 11 | : when 'premium' { 12 | var AIR_ISU_REFRESH_INTERVAL = 10000; 13 | : } 14 | : } 15 | -------------------------------------------------------------------------------- /webapp/php/.hold: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isucon/isucon5-final/981f7721e94e655280d71f70f64fa13b94181128/webapp/php/.hold -------------------------------------------------------------------------------- /webapp/php/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "slim/slim": "2.*", 4 | "guzzlehttp/guzzle": "6.*" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /webapp/php/composer.phar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isucon/isucon5-final/981f7721e94e655280d71f70f64fa13b94181128/webapp/php/composer.phar -------------------------------------------------------------------------------- /webapp/php/nginx.php.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | 3 | events { 4 | worker_connections 1024; 5 | } 6 | 7 | http { 8 | include /etc/nginx/mime.types; 9 | types_hash_max_size 2048; 10 | 11 | upstream php-fpm { 12 | server 127.0.0.1:8080; 13 | } 14 | 15 | server { 16 | location ~ ^/(css|fonts|js) { 17 | root /home/isucon/webapp/static; 18 | } 19 | 20 | location / { 21 | root /home/isucon/webapp/php; 22 | 23 | fastcgi_pass php-fpm; 24 | fastcgi_index index.php; 25 | fastcgi_read_timeout 120; 26 | 27 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 28 | fastcgi_param QUERY_STRING $query_string; 29 | fastcgi_param REQUEST_METHOD $request_method; 30 | fastcgi_param CONTENT_TYPE $content_type; 31 | fastcgi_param CONTENT_LENGTH $content_length; 32 | 33 | fastcgi_param SCRIPT_NAME $fastcgi_script_name; 34 | fastcgi_param REQUEST_URI $request_uri; 35 | fastcgi_param DOCUMENT_URI $document_uri; 36 | fastcgi_param DOCUMENT_ROOT $document_root; 37 | fastcgi_param SERVER_PROTOCOL $server_protocol; 38 | fastcgi_param HTTPS $https if_not_empty; 39 | 40 | fastcgi_param GATEWAY_INTERFACE CGI/1.1; 41 | fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; 42 | 43 | fastcgi_param REMOTE_ADDR $http_x_forwarded_for; 44 | fastcgi_param REMOTE_PORT $remote_port; 45 | fastcgi_param SERVER_ADDR $server_addr; 46 | fastcgi_param SERVER_PORT $server_port; 47 | fastcgi_param SERVER_NAME $server_name; 48 | 49 | fastcgi_param REDIRECT_STATUS 200; 50 | 51 | rewrite ^(.*)$ /index.php?$1 break; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /webapp/php/php-fpm.conf: -------------------------------------------------------------------------------- 1 | daemonize = no 2 | 3 | [www] 4 | user = isucon 5 | group = isucon 6 | listen = 0.0.0.0:8080 7 | 8 | pm = dynamic 9 | pm.max_children = 4 10 | pm.start_servers = 4 11 | pm.min_spare_servers = 4 12 | pm.max_spare_servers = 4 13 | pm.process_idle_timeout = 10s; 14 | pm.max_requests = 500 15 | pm.status_path = /status 16 | ping.path = /ping 17 | 18 | catch_workers_output = true 19 | -------------------------------------------------------------------------------- /webapp/php/templates/login.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AirISU Sign in 10 | 11 | 12 | 13 | 14 | 15 |
16 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /webapp/php/templates/main.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AirISU 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | 24 |

AirISU:

25 |
26 | 27 |
28 |
29 | 30 |
31 |

© ISU Company 2015

32 |
33 | 34 |
35 | 36 | 54 | 55 | 63 | 64 | 65 | 66 | 67 | 68 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /webapp/php/templates/signup.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AirISU Signup 10 | 11 | 12 | 13 | 14 | 15 |
16 | 33 |
34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /webapp/php/templates/userjs.php: -------------------------------------------------------------------------------- 1 | var AIR_ISU_REFRESH_INTERVAL = ; 16 | -------------------------------------------------------------------------------- /webapp/python/.hold: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isucon/isucon5-final/981f7721e94e655280d71f70f64fa13b94181128/webapp/python/.hold -------------------------------------------------------------------------------- /webapp/python/views/login.tpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AirISU Sign in 10 | 11 | 12 | 13 | 14 | 15 |
16 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /webapp/python/views/main.tpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AirISU 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | 24 |

AirISU: {{user["email"]}}

25 |
26 | 27 |
28 |
29 | 30 |
31 |

© ISU Company 2015

32 |
33 | 34 |
35 | 36 | 54 | 55 | 63 | 64 | 65 | 66 | 67 | 68 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /webapp/python/views/signup.tpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AirISU Signup 10 | 11 | 12 | 13 | 14 | 15 |
16 | 33 |
34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /webapp/python/views/userjs.tpl: -------------------------------------------------------------------------------- 1 | var AIR_ISU_REFRESH_INTERVAL = {{grade}}; -------------------------------------------------------------------------------- /webapp/ruby/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "sinatra" 4 | gem "sinatra-contrib" 5 | gem "pg" 6 | gem "erubis" 7 | gem "unicorn" 8 | gem "httpclient" 9 | -------------------------------------------------------------------------------- /webapp/ruby/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | backports (3.6.6) 5 | erubis (2.7.0) 6 | httpclient (2.6.0.1) 7 | kgio (2.10.0) 8 | multi_json (1.11.2) 9 | pg (0.18.3) 10 | rack (1.6.4) 11 | rack-protection (1.5.3) 12 | rack 13 | rack-test (0.6.3) 14 | rack (>= 1.0) 15 | raindrops (0.15.0) 16 | sinatra (1.4.6) 17 | rack (~> 1.4) 18 | rack-protection (~> 1.4) 19 | tilt (>= 1.3, < 3) 20 | sinatra-contrib (1.4.6) 21 | backports (>= 2.0) 22 | multi_json 23 | rack-protection 24 | rack-test 25 | sinatra (~> 1.4.0) 26 | tilt (>= 1.3, < 3) 27 | tilt (2.0.1) 28 | unicorn (4.9.0) 29 | kgio (~> 2.6) 30 | rack 31 | raindrops (~> 0.7) 32 | 33 | PLATFORMS 34 | ruby 35 | 36 | DEPENDENCIES 37 | erubis 38 | httpclient 39 | pg 40 | sinatra 41 | sinatra-contrib 42 | unicorn 43 | 44 | BUNDLED WITH 45 | 1.10.6 46 | -------------------------------------------------------------------------------- /webapp/ruby/config.ru: -------------------------------------------------------------------------------- 1 | require_relative './app.rb' 2 | 3 | run Isucon5f::WebApp 4 | -------------------------------------------------------------------------------- /webapp/ruby/unicorn_config.rb: -------------------------------------------------------------------------------- 1 | worker_processes 4 2 | preload_app true 3 | listen 8080 4 | # pid "/home/isucon/webapp/ruby/unicorn.pid" 5 | -------------------------------------------------------------------------------- /webapp/ruby/views/login.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AirISU Sign in 10 | 11 | 12 | 13 | 14 | 15 |
16 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /webapp/ruby/views/main.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AirISU 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | 24 |

AirISU: <%= user[:email] %>

25 |
26 | 27 |
28 |
29 | 30 |
31 |

© ISU Company 2015

32 |
33 | 34 |
35 | 36 | 54 | 55 | 63 | 64 | 65 | 66 | 67 | 68 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /webapp/ruby/views/signup.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AirISU Signup 10 | 11 | 12 | 13 | 14 | 15 |
16 | 33 |
34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /webapp/ruby/views/userjs.erb: -------------------------------------------------------------------------------- 1 | var AIR_ISU_REFRESH_INTERVAL = <%= case grade when 'micro' then 30000 when 'small' then 30000 when 'standard' then 20000 when 'premium' then 10000 end %>; 2 | -------------------------------------------------------------------------------- /webapp/scala/.hold: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isucon/isucon5-final/981f7721e94e655280d71f70f64fa13b94181128/webapp/scala/.hold -------------------------------------------------------------------------------- /webapp/scala/README.md: -------------------------------------------------------------------------------- 1 | isucon5-final-scala 2 | === 3 | 4 | Scala-based example application for the ISUCON5 final round. 5 | 6 | ISUCON5決勝アプリケーションのScalaによる参考実装です。 7 | 8 | ## Development notes (開発ノート) 9 | 10 | To start the development, use `~container:restart` command. 11 | With this command you can automatically reload the web application as you modify the source code: 12 | 13 | 開発を始めるには、`~container:restart`コマンドを使用します。 14 | コードを修正するたびにウェブアプリケーションがリロードされます。 15 | 16 | ``` 17 | $ ./sbt 18 | > ~container:restart 19 | ``` 20 | 21 | You can access the web application from 22 | 23 | 起動したウェブアプリケーションには からアクセスできます。 24 | 25 | ### Run as a standalone web server スタンドアローンサーバーとして起動する 26 | ``` 27 | # Generates a start-up script of your web application ウェブアプリケーションの起動スクリプトを生成 28 | $ ./sbt launcher 29 | 30 | # Launch a jetty-based web server Jettyウェブサーバーを起動 31 | $ ./target/launcher 32 | 33 | # Change the port number 使用するポート番号を変更する 34 | $ ./target/launcher 8081 35 | 36 | ``` 37 | 38 | To use your own Java-based web server (e.g., Tomcat), you can create a war (web archive) file with `sbt package` command: 39 | 40 | 独自のJavaウェブサーバー(Tomcatなど)を利用するために、warファイルを`sbt package`コマンドで生成することもできます。 41 | ``` 42 | $ ./sbt package 43 | ``` 44 | 45 | -------------------------------------------------------------------------------- /webapp/scala/build.sbt: -------------------------------------------------------------------------------- 1 | import java.io.File 2 | 3 | servletSettings 4 | 5 | scalariformSettings 6 | 7 | com.typesafe.sbt.SbtStartScript.startScriptForClassesSettings 8 | 9 | name := "isucon5-final-scala" 10 | 11 | version := "1.0" 12 | 13 | crossPaths := false 14 | 15 | scalaVersion := "2.11.7" 16 | 17 | lazy val skinnyMicroVersion = "0.9.12" 18 | 19 | resolvers += "sonatype releases" at "https://oss.sonatype.org/content/repositories/releases" 20 | 21 | // for Scalate 22 | dependencyOverrides := Set("org.scala-lang" % "scala-compiler" % scalaVersion.value) 23 | 24 | libraryDependencies ++= Seq( 25 | // micro Web framework 26 | "org.skinny-framework" %% "skinny-micro" % skinnyMicroVersion, 27 | "org.skinny-framework" %% "skinny-micro-scalate" % skinnyMicroVersion, 28 | // Standalone Web server (Jetty 9.2 / Servlet 3.1) 29 | "org.skinny-framework" %% "skinny-micro-server" % skinnyMicroVersion, 30 | "org.eclipse.jetty" % "jetty-webapp" % "9.2.13.v20150730" % "container", 31 | "ch.qos.logback" % "logback-classic" % "1.1.3", 32 | "org.postgresql" % "postgresql" % "9.4-1201-jdbc41", 33 | "org.json4s" %% "json4s-native" % "3.3.0", 34 | "org.xerial" % "xerial-core" % "3.3.8", 35 | "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.6.1", 36 | "com.github.nscala-time" %% "nscala-time" % "2.2.0" 37 | ) 38 | 39 | mainClass in Compile := Some("skinny.standalone.JettyLauncher") 40 | 41 | // add src/main/webapp to unmanaged resources for sbt-start-script 42 | unmanagedResourceDirectories in Compile <++= baseDirectory { base => 43 | Seq(base / "../static") ++ sys.env.get("LOCAL_DEV").map(_ => Seq.empty).getOrElse(Seq(base / "src/main/webapp")) 44 | } 45 | 46 | webappResources in Compile += baseDirectory.value / "../static" 47 | 48 | scalacOptions ++= Seq("-unchecked", "-deprecation", "-feature") 49 | 50 | lazy val launcher = taskKey[File]("launcher generation task") 51 | 52 | launcher := { 53 | val s = streams.value 54 | val runtimeClassPaths = (dependencyClasspath in Runtime).value 55 | val cpStr = runtimeClassPaths.seq.map(_.data.getAbsolutePath).mkString(java.io.File.pathSeparator) 56 | // Ensure running compile task to generate target/classes folder 57 | (compile in Compile).value 58 | val staticWebappResoruce = target.value / "webapp" 59 | val script = 60 | s"""#!/bin/bash 61 | |PROJECT_DIR=$$(cd "$${BASH_SOURCE[0]%/*}" && pwd -P)/.. 62 | |MAINCLASS=isucon5.JettyLauncher 63 | | 64 | |exec java $$JAVA_OPTS -cp "${cpStr}" \\ 65 | |"$$MAINCLASS" "$$@" 66 | |""".stripMargin 67 | val launcherFile = target.value / "launcher" 68 | IO.write(launcherFile, script) 69 | launcherFile.setExecutable(true) 70 | s.log.info(s"Generated ${launcherFile}") 71 | launcherFile 72 | } 73 | -------------------------------------------------------------------------------- /webapp/scala/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | scalacOptions ++= Seq("-unchecked", "-deprecation", "-feature") 2 | 3 | addSbtPlugin("org.skinny-framework" % "sbt-servlet-plugin" % "2.0.1") 4 | 5 | addSbtPlugin("com.typesafe.sbt" % "sbt-scalariform" % "1.3.0") 6 | 7 | addSbtPlugin("com.typesafe.sbt" % "sbt-start-script" % "0.10.0") 8 | -------------------------------------------------------------------------------- /webapp/scala/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %date %highlight(%level [%thread] %logger{64} %msg) %n 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /webapp/scala/src/main/scala/Bootstrap.scala: -------------------------------------------------------------------------------- 1 | 2 | import javax.servlet.ServletContext 3 | 4 | import isucon5.Isucon5 5 | import skinny.micro._ 6 | 7 | class Bootstrap extends LifeCycle { 8 | 9 | override def init(ctx: ServletContext) { 10 | Isucon5.mount(ctx) 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /webapp/scala/src/main/scala/isucon5/JettyLauncher.scala: -------------------------------------------------------------------------------- 1 | package isucon5 2 | 3 | import javax.servlet.ServletContextListener 4 | 5 | import org.eclipse.jetty.server.Server 6 | import org.eclipse.jetty.servlet.DefaultServlet 7 | import org.eclipse.jetty.webapp.WebAppContext 8 | import skinny.logging.LoggerProvider 9 | import skinny.micro.SkinnyListener 10 | 11 | object JettyLauncher extends JettyServer { 12 | def main(args: Array[String]): Unit = { 13 | if (args.length > 0) { 14 | val port = args(0) 15 | System.setProperty("skinny.port", port) 16 | } 17 | 18 | run() 19 | } 20 | } 21 | 22 | trait JettyServer extends LoggerProvider { 23 | 24 | def listener(listener: ServletContextListener): JettyServer = { 25 | this.listener = listener 26 | this 27 | } 28 | 29 | def port(port: Int): JettyServer = { 30 | _port = port 31 | this 32 | } 33 | 34 | def run() = { 35 | start() 36 | server.join 37 | } 38 | 39 | def start(): Unit = { 40 | refreshServer() 41 | logger.info(s"Starting Jetty server on port ${port}") 42 | val context = new WebAppContext() 43 | val contextPath = sys.env.get("SKINNY_PREFIX").orElse(getEnvVarOrSysProp("skinny.prefix")).getOrElse("/") 44 | context.setContextPath(contextPath) 45 | context.setWar({ 46 | val domain = this.getClass.getProtectionDomain 47 | val location = domain.getCodeSource.getLocation 48 | location.toExternalForm 49 | }) 50 | context.addEventListener(listener) 51 | context.addServlet(classOf[DefaultServlet], "/") 52 | server.setHandler(context) 53 | 54 | server.start 55 | logger.info(s"Started Jetty server on port ${port}") 56 | } 57 | 58 | def stop(): Unit = { 59 | if (server != null) { 60 | server.stop() 61 | } 62 | } 63 | 64 | private[this] var server: Server = _ 65 | 66 | private[this] var listener: ServletContextListener = new SkinnyListener 67 | 68 | private[this] var _port: Int = { 69 | // PORT: Heroku default env varaible 70 | Option(System.getenv("PORT")).map(_.toInt).getOrElse(8080) 71 | } 72 | 73 | private[this] def port: Int = { 74 | val port = sys.env.get("SKINNY_PORT").orElse(getEnvVarOrSysProp("skinny.port")).map(_.toInt).getOrElse(_port) 75 | port 76 | } 77 | 78 | private[this] def newServer(port: Int): Server = new Server(port) 79 | 80 | private[this] def refreshServer(): Unit = { 81 | if (server != null) { 82 | stop() 83 | server.destroy() 84 | server.synchronized { 85 | server = newServer(port) 86 | } 87 | } else { 88 | server = newServer(port) 89 | } 90 | } 91 | 92 | private[this] def getEnvVarOrSysProp(key: String): Option[String] = { 93 | sys.env.get(key).orElse(sys.props.get(key)) 94 | } 95 | 96 | } 97 | 98 | -------------------------------------------------------------------------------- /webapp/scala/src/main/webapp/WEB-INF/scalate/layouts/default.ssp: -------------------------------------------------------------------------------- 1 | <%@ val body:String %> 2 | <%@ var title:String = "AirISU" %> 3 | 4 | 5 | ${unescape(body)} 6 | -------------------------------------------------------------------------------- /webapp/scala/src/main/webapp/WEB-INF/views/login.ssp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | AirISU Sign in 8 | 9 | 10 | 11 | 12 |
13 | 21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /webapp/scala/src/main/webapp/WEB-INF/views/main.ssp: -------------------------------------------------------------------------------- 1 | <%@ val user: isucon5.User %> 2 | 3 | 4 | 5 | 6 | 7 | 8 | AirISU 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 | 23 |

AirISU: <%= user.email %>

24 |
25 | 26 |
27 |
28 | 29 |
30 |

© ISU Company 2015

31 |
32 | 33 |
34 | 35 | 53 | 54 | 62 | 63 | 64 | 65 | 66 | 67 | 72 | -------------------------------------------------------------------------------- /webapp/scala/src/main/webapp/WEB-INF/views/signup.ssp: -------------------------------------------------------------------------------- 1 | <%@ var title:String = "AirISU Signup" %> 2 | 3 | 4 | 5 | 6 | 7 | 8 | AirISU Signup 9 | 10 | 11 | 12 | 13 |
14 | 31 |
32 | 33 | -------------------------------------------------------------------------------- /webapp/scala/src/main/webapp/WEB-INF/views/userjs.ssp: -------------------------------------------------------------------------------- 1 | <% attributes("layout") = "" %> 2 | <%@ val grade:isucon5.Grade %> 3 | var AIR_ISU_REFRESH_INTERVAL = <%= grade.toString match { case "micro" => "30000"; case "small" => "30000"; case "standard" => "20000"; case "premium" => "10000"}%>; -------------------------------------------------------------------------------- /webapp/scala/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | skinny.micro.SkinnyListener 8 | 9 | 10 | 11 | COOKIE 12 | 13 | 14 | -------------------------------------------------------------------------------- /webapp/sql/.hold: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isucon/isucon5-final/981f7721e94e655280d71f70f64fa13b94181128/webapp/sql/.hold -------------------------------------------------------------------------------- /webapp/sql/schema.sql: -------------------------------------------------------------------------------- 1 | -- CREATE USER isucon; 2 | -- CREATE DATABASE isucon5f OWNER isucon ENCODING 'utf8'; 3 | 4 | -- \connect isucon5f 5 | 6 | CREATE TYPE grades AS ENUM ('micro', 'small', 'standard', 'premium'); 7 | 8 | CREATE TABLE users ( 9 | id SERIAL PRIMARY KEY, 10 | email VARCHAR(256) NOT NULL, 11 | salt VARCHAR(32) NOT NULL, 12 | passhash bytea NOT NULL, 13 | grade grades 14 | ); 15 | 16 | -- CREATE EXTENSION pgcrypto; 17 | 18 | CREATE TYPE token_types AS ENUM ('header', 'param'); 19 | 20 | CREATE TABLE endpoints ( 21 | service VARCHAR(32) NOT NULL PRIMARY KEY, 22 | meth VARCHAR(16) NOT NULL, 23 | token_type token_types, 24 | token_key VARCHAR(64), 25 | uri TEXT 26 | ); 27 | 28 | CREATE TABLE subscriptions ( 29 | user_id INTEGER REFERENCES users (id) NOT NULL PRIMARY KEY, 30 | arg TEXT 31 | ); 32 | -------------------------------------------------------------------------------- /webapp/static/.hold: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isucon/isucon5-final/981f7721e94e655280d71f70f64fa13b94181128/webapp/static/.hold -------------------------------------------------------------------------------- /webapp/static/css/jumbotron-narrow.css: -------------------------------------------------------------------------------- 1 | /* Space out content a bit */ 2 | body { 3 | padding-top: 20px; 4 | padding-bottom: 20px; 5 | } 6 | 7 | /* Everything but the jumbotron gets side spacing for mobile first views */ 8 | .header, 9 | .marketing, 10 | .footer { 11 | padding-right: 15px; 12 | padding-left: 15px; 13 | } 14 | 15 | /* Custom page header */ 16 | .header { 17 | padding-bottom: 20px; 18 | border-bottom: 1px solid #e5e5e5; 19 | } 20 | /* Make the masthead heading the same height as the navigation */ 21 | .header h3 { 22 | margin-top: 0; 23 | margin-bottom: 0; 24 | line-height: 40px; 25 | } 26 | 27 | /* Custom page footer */ 28 | .footer { 29 | padding-top: 19px; 30 | color: #777; 31 | border-top: 1px solid #e5e5e5; 32 | } 33 | 34 | /* Customize container */ 35 | @media (min-width: 768px) { 36 | .container { 37 | max-width: 730px; 38 | } 39 | } 40 | .container-narrow > hr { 41 | margin: 30px 0; 42 | } 43 | 44 | /* Main marketing message and sign up button */ 45 | .jumbotron { 46 | text-align: center; 47 | border-bottom: 1px solid #e5e5e5; 48 | } 49 | .jumbotron .btn { 50 | padding: 6px 10px; 51 | font-size: 14px; 52 | } 53 | 54 | /* Supporting marketing content */ 55 | .marketing { 56 | margin: 10px 0; 57 | } 58 | .marketing p + h4 { 59 | margin-top: 12px; 60 | } 61 | 62 | /* Responsive: Portrait tablets and up */ 63 | @media screen and (min-width: 768px) { 64 | /* Remove the padding we set earlier */ 65 | .header, 66 | .marketing, 67 | .footer { 68 | padding-right: 0; 69 | padding-left: 0; 70 | } 71 | /* Space out the masthead */ 72 | .header { 73 | margin-bottom: 30px; 74 | } 75 | /* Remove the bottom border on the jumbotron for visual effect */ 76 | .jumbotron { 77 | border-bottom: 0; 78 | padding-top: 10px; 79 | padding-bottom: 10px; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /webapp/static/css/signin.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 40px; 3 | padding-bottom: 40px; 4 | background-color: #eee; 5 | } 6 | 7 | .form-signin { 8 | max-width: 330px; 9 | padding: 15px; 10 | margin: 0 auto; 11 | } 12 | .form-signin .form-signin-heading, 13 | .form-signin .checkbox { 14 | margin-bottom: 10px; 15 | } 16 | .form-signin .checkbox { 17 | font-weight: normal; 18 | } 19 | .form-signin .form-control { 20 | position: relative; 21 | height: auto; 22 | -webkit-box-sizing: border-box; 23 | -moz-box-sizing: border-box; 24 | box-sizing: border-box; 25 | padding: 10px; 26 | font-size: 16px; 27 | } 28 | .form-signin .form-control:focus { 29 | z-index: 2; 30 | } 31 | .form-signin input[type="email"] { 32 | margin-bottom: -1px; 33 | border-bottom-right-radius: 0; 34 | border-bottom-left-radius: 0; 35 | } 36 | .form-signin input[type="password"] { 37 | margin-bottom: 10px; 38 | border-top-left-radius: 0; 39 | border-top-right-radius: 0; 40 | } 41 | -------------------------------------------------------------------------------- /webapp/static/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isucon/isucon5-final/981f7721e94e655280d71f70f64fa13b94181128/webapp/static/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /webapp/static/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isucon/isucon5-final/981f7721e94e655280d71f70f64fa13b94181128/webapp/static/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /webapp/static/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isucon/isucon5-final/981f7721e94e655280d71f70f64fa13b94181128/webapp/static/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /webapp/static/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isucon/isucon5-final/981f7721e94e655280d71f70f64fa13b94181128/webapp/static/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /webapp/static/js/airisu.js: -------------------------------------------------------------------------------- 1 | $(function(){ 2 | window.setInterval(function(){ 3 | $.get('/data', function(data){ render(data); }); 4 | }, AIR_ISU_REFRESH_INTERVAL); 5 | $.get('/data', function(data){ render(data); }); 6 | }); 7 | 8 | function render(list) { 9 | $('#api-response-container .api-result').remove(); 10 | var api_results = []; 11 | list.forEach(function(item){ 12 | var element = $('#api-result-template-container .api-result').clone(); 13 | switch(item.service) { 14 | case 'ken': 15 | case 'ken2': render_ken(element, item.data); break; 16 | case 'surname': 17 | case 'givenname': render_name(element, item.data); break; 18 | case 'tenki': render_tenki(element, item.data); break; 19 | case 'perfectsec': render_perfectsec(element, item.data); break; 20 | case 'perfectsec_attacked': render_perfectsec_attacked(element, item.data); break; 21 | default: console.log("unknown api response, service:" + item.service); console.log(item.data); 22 | } 23 | $('#api-response-container').append(element); 24 | }); 25 | } 26 | 27 | function render_tenki(element, data){ 28 | $(element).find('h4').text("Updated: " + data.date); 29 | $(element).find('p').text(data.yoho); 30 | } 31 | 32 | function render_perfectsec(element, data){ 33 | $(element).find('h4').text("Request: " + data.req); 34 | $(element).find('p').text("KEY: " + data.key + ", TOKEN: " + data.onetime_token); 35 | } 36 | 37 | function render_perfectsec_attacked(element, data){ 38 | var updatedAt = new Date(data.updated_at * 1000); 39 | $(element).find('h4').text("updated: " + updatedAt.toISOString()); 40 | $(element).find('p').text(data.key1 + ", " + data.key2 + ", " + data.key3); 41 | } 42 | 43 | function render_ken(element, data){ 44 | $(element).find('h4').text("KEN: " + data.zipcode); 45 | $(element).find('p').text(data.addresses.join(", ")); 46 | } 47 | 48 | function render_name(element, data){ 49 | $(element).find('h4').text("NAME: " + data.query); 50 | var names = []; 51 | data.result.forEach(function(item){ 52 | var yomi = item.yomi; 53 | var name = item.name; 54 | names.push(name + "(" + yomi + ")"); 55 | }); 56 | $(element).find('p').text(names.join(", ")); 57 | } 58 | 59 | -------------------------------------------------------------------------------- /webapp/static/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') --------------------------------------------------------------------------------