Skip to content

Commit 4cc3269

Browse files
committed
publish
0 parents  commit 4cc3269

File tree

236 files changed

+35525
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

236 files changed

+35525
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*~
2+
.DS_Store

.project

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<projectDescription>
3+
<name>isucon2</name>
4+
<comment></comment>
5+
<projects>
6+
</projects>
7+
<buildSpec>
8+
<buildCommand>
9+
<name>org.eclipse.wst.common.project.facet.core.builder</name>
10+
<arguments>
11+
</arguments>
12+
</buildCommand>
13+
</buildSpec>
14+
<natures>
15+
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
16+
</natures>
17+
</projectDescription>

README.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# ISUCON 2 #
2+
3+
CAUTION: this project is open for only #isucon administrators
4+
5+
## web app ##
6+
7+
- /webapp/perl
8+
- /webapp/php
9+
- /webapp/nodejs
10+
- /webapp/ruby
11+
- /webapp/python
12+
- /webapp/java
13+
14+
### Webアプリの基本方針 ###
15+
16+
- 処理はすべてリクエストを受け取ってから実施する
17+
- DBへのクエリ
18+
- テンプレートからのレンダリング
19+
- 全てのコンテンツをアプリケーションから渡す
20+
- js/css/画像も含めて
21+
- キャッシュ等はとりあえず全て無し
22+
23+
### 実装するリクエストハンドラ ###
24+
25+
- `/`
26+
- GET
27+
- artistのリスト
28+
- `SELECT * FROM artist ORDER BY id`
29+
30+
- `/artist/:artistid`
31+
- GET
32+
- ticketのリスト 合計の残り枚数表示
33+
- `SELECT id, name FROM artist WHERE id = ? LIMIT 1`
34+
- `SELECT id, name FROM ticket WHERE artist_id = ? ORDER BY id`
35+
- `SELECT COUNT(*) FROM variation INNER JOIN stock ON stock.variation_id = variation.id WHERE variation.ticket_id = ? AND stock.order_id IS NULL`
36+
37+
- `/ticket/:ticket`
38+
- GET
39+
- variationのリスト 各種残り枚数表示
40+
- `SELECT t.*, a.name AS artist_name FROM ticket t INNER JOIN artist a ON t.artist_id = a.id WHERE t.id = ? LIMIT 1`
41+
- `SELECT id, name FROM variation WHERE ticket_id = ? ORDER BY id`
42+
- `SELECT seat_id, order_id FROM stock WHERE variation_id = ?`
43+
- `SELECT COUNT(*) FROM stock WHERE variation_id = ? AND order_id IS NULL`
44+
45+
- `/buy`
46+
- POST
47+
- チケットの購入 stockの在庫を1つ抑え席番を表示 `member_id`を受け取り`order_request`に保存
48+
- `START TRANSACTION`
49+
- `INSERT INTO order_request (member_id) VALUES (?)`
50+
- `UPDATE stock SET order_id = ? WHERE variation_id = ? AND order_id IS NULL ORDER BY RAND() LIMIT 1`
51+
- `COMMIT`
52+
53+
- なお、全ページ左側のサイドバーに「最近購入されたチケット10件」を表示
54+
- ```
55+
SELECT stock.seat_id, variation.name AS v_name, ticket.name AS t_name, artist.name AS a_name FROM stock
56+
JOIN variation ON stock.variation_id = variation.id
57+
JOIN ticket ON variation.ticket_id = ticket.id
58+
JOIN artist ON ticket.artist_id = artist.id
59+
WHERE order_id IS NOT NULL
60+
ORDER BY order_id DESC LIMIT 10
61+
```
62+
63+
### staticファイル ###
64+
65+
- images
66+
- isucon_title ロゴ
67+
- js
68+
- jquery 最新版minified
69+
- jquery-ui 最新版minified
70+
- isucon2.js
71+
- css
72+
- jquery-ui ui-lightness
73+
- isucon2.css デザイン調整用
74+
75+
## benchmark tool ##
76+
77+
- /tools

tools/.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
http_load/http_load-12mar2006
2+
http_load_isucon2/http_load
3+
http_load_isucon2/*.o
4+
urlfile
5+
node_modules

tools/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# benchmark tools #
2+
3+
$ npm install
4+
$ ./bench.js subcommand PARALLELS SECONDS TARGET_IP TARGET_PORT TARGET_ARTIST_ID TARGET_TICKET_ID

tools/agent.js

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
var async = require('async'),
2+
fs = require('fs'),
3+
http = require('http'),
4+
child = require('child_process');
5+
6+
var express = require('express'),
7+
app = express();
8+
9+
var config = JSON.parse(fs.readFileSync(__dirname + '/agent.json'));
10+
11+
var BENCH_AGENT_PING_STARTING = 2000,
12+
BENCH_AGENT_PING_INTERVAL = 5000;
13+
14+
// app.use(express.logger());
15+
app.use(express.bodyParser()); /* json, urlencoded, multipart */
16+
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
17+
18+
var maxSlots = {primary:config.slots.primary, secondary:config.slots.secondary};
19+
var slots = {primary:config.slots.primary, secondary:config.slots.secondary};
20+
21+
app.get('/status', function(req, res){ /* returns slot status */
22+
res.json(slots);
23+
});
24+
25+
function command(subcmd, parallels, seconds, ip, port, artist, ticket) {
26+
return ['node bench.js', subcmd, parallels, seconds, ip, port, artist, ticket].join(' ');
27+
};
28+
29+
function execSubCommand(subcmd, params, callback) {
30+
var parallels = params.parallels,
31+
seconds = params.seconds,
32+
ip = params.ip,
33+
port = params.port,
34+
artist = params.artist,
35+
ticket = params.ticket;
36+
var p = child.exec(
37+
command(subcmd, parallels, seconds, ip, port, artist, ticket),
38+
{ maxBuffer: 1000 * 1024 },
39+
function(err, stdout, stderr){
40+
if (err) {
41+
// JSON.stringify([Error] object) is drop 'message' attribute...
42+
var error = {message:'agent bench command execute error, code:' + err.code};
43+
callback({err:error});
44+
return;
45+
}
46+
if (stderr && stderr.length > 0) {
47+
console.log(JSON.stringify({
48+
date: (new Date()),
49+
param: {subcmd:subcmd,parallels:parallels,seconds:seconds},
50+
target: {ip:ip,port:port,artist:artist,ticket:ticket},
51+
stdout:stdout,
52+
stderr:stderr
53+
}, null, ' '));
54+
}
55+
callback(JSON.parse(stdout));
56+
}
57+
);
58+
return p;
59+
};
60+
61+
function getSlot() {
62+
if (slots.primary > 0) {
63+
slots.primary -= 1;
64+
return true;
65+
}
66+
if (slots.secondary > 0) {
67+
slots.secondary -= 1;
68+
return true;
69+
}
70+
return false;
71+
};
72+
73+
function releaseSlot() {
74+
if (slots.secondary < maxSlots.secondary) {
75+
slots.secondary += 1;
76+
return;
77+
}
78+
slots.primary += 1;
79+
};
80+
81+
var runnings = {};
82+
83+
app.post('/:subcmd/:benchid/:sessionid/:parallels/:seconds/:ip/:port/:artist/:ticket', function(req,res){
84+
var subcmd = req.params.subcmd,
85+
benchid = req.params.benchid,
86+
sessionid = req.params.sessionid;
87+
if (! getSlot()) { res.json(400, {err:'no more slots available for subcommand:' + subcmd}); return; }
88+
89+
var child = execSubCommand(subcmd, req.params, function(result){
90+
releaseSlot();
91+
if (runnings[sessionid]) {
92+
/* send result to manager */
93+
delete runnings[sessionid];
94+
if (config.manager.skip) {
95+
console.log(JSON.stringify({sessionid:sessionid,result:result}, null, ' '));
96+
} else {
97+
sendResult({benchid:benchid,sessionid:sessionid,result:result});
98+
}
99+
} else { // session killed
100+
// nothing to do
101+
}
102+
});
103+
runnings[sessionid] = child;
104+
res.json(200, {});
105+
});
106+
107+
app.post('/kill/:sessionid', function(req,res){
108+
var sessionid = req.params.sessionid;
109+
if (runnings[sessionid]) {
110+
runnings[sessionid].kill('SIGTERM');
111+
delete runnings[sessionid];
112+
releaseSlot();
113+
}
114+
res.json(200, {});
115+
});
116+
117+
function uriEncodeForFormData(str){
118+
// see: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/encodeURIComponent
119+
return encodeURIComponent(str).replace(/%20/g, '+');
120+
};
121+
function generateFormBody(obj){
122+
var pairs = [];
123+
for (var key in obj){
124+
pairs.push(uriEncodeForFormData(key) + '=' + uriEncodeForFormData(obj[key]));
125+
}
126+
return pairs.join('&');
127+
};
128+
/* in init sequence, communicate with manager, and get */
129+
function postManager(path, data, type){
130+
var headers = { 'User-Agent': 'Isucon2 Bench Agent RPC' };
131+
var body;
132+
if (!type || type === 'form') {
133+
body = generateFormBody(data);
134+
headers['Content-Type'] = 'application/x-www-form-urlencoded';
135+
} else if (type === 'json') {
136+
body = JSON.stringify(data);
137+
headers['Content-Type'] = 'application/json';
138+
} else {
139+
throw {message:'unknown format for postManager:type'};
140+
}
141+
headers['Content-Length'] = (new Buffer(body, 'utf8')).length;
142+
143+
var options = {
144+
host: config.manager.address,
145+
port: config.manager.port,
146+
path: path,
147+
headers: headers,
148+
method: 'POST'
149+
};
150+
var req = http.request(options, function(res){
151+
if (res.statusCode !== 200)
152+
console.log('Error, Isucon2 manager returns code:' + res.statusCode + ', for path:' + path);
153+
});
154+
req.on('error', function(err){
155+
console.log('Error, Failed to send status to Isucon2 manager for path:' + path);
156+
console.log(err);
157+
});
158+
req.end(body);
159+
}
160+
161+
function sendStatus(){
162+
postManager('/ping', {port:config.agent.port, primary:slots.primary, secondary:slots.secondary});
163+
};
164+
function sendResult(data){
165+
postManager('/result', data, 'json');
166+
};
167+
168+
if (!config.agent || !config.manager || !config.slots) {
169+
if (!config.testing) {
170+
console.log('Fatal, manager address and/or agent slots information missing.');
171+
process.exit(1);
172+
}
173+
}
174+
setTimeout(function(){
175+
if (config.manager.skip) {
176+
console.log('WARNING: Skipping to send status to manager by configuration config.manager.skip');
177+
return;
178+
}
179+
sendStatus();
180+
setInterval(sendStatus, BENCH_AGENT_PING_INTERVAL);
181+
}, BENCH_AGENT_PING_STARTING);
182+
183+
app.listen(config.agent.port);

tools/agent.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"manager": {
3+
"skip": false,
4+
"address": "localhost",
5+
"port": 5001
6+
},
7+
"agent": {
8+
"port": 5002
9+
},
10+
"slots": {
11+
"primary": 4,
12+
"secondary": 1
13+
},
14+
"testing": false
15+
}

tools/agent.production.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"manager": {
3+
"skip": false,
4+
"address": "125.6.152.241",
5+
"port": 5001
6+
},
7+
"agent": {
8+
"port": 5002
9+
},
10+
"slots": {
11+
"primary": 30,
12+
"secondary": 2
13+
},
14+
"testing": false
15+
}

0 commit comments

Comments
 (0)