001: /*
002: * Copyright (c) 2001 by Matt Welsh and The Regents of the University of
003: * California. All rights reserved.
004: *
005: * Permission to use, copy, modify, and distribute this software and its
006: * documentation for any purpose, without fee, and without written agreement is
007: * hereby granted, provided that the above copyright notice and the following
008: * two paragraphs appear in all copies of this software.
009: *
010: * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
011: * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
012: * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
013: * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
014: *
015: * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
016: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
017: * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
018: * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
019: * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
020: *
021: * Author: Matt Welsh <mdw@cs.berkeley.edu>
022: *
023: */
024:
025: package seda.apps.Haboob.cache;
026:
027: import seda.apps.Haboob.*;
028: import seda.sandStorm.api.*;
029: import seda.sandStorm.core.*;
030: import seda.sandStorm.lib.http.*;
031: import seda.sandStorm.lib.aSocket.*;
032: import seda.sandStorm.lib.aDisk.*;
033: import seda.util.*;
034: import java.io.*;
035: import java.util.*;
036:
037: /**
038: * This stage responds to HTTP requests with static pages.
039: * This is meant to be used for debugging only.
040: */
041: public class StaticPage implements EventHandlerIF, HaboobConst {
042:
043: private static final boolean DEBUG = false;
044:
045: // Size of static page in bytes
046: private static final int DEBUG_STATIC_PAGE_SIZE = 8192;
047: // Send static page as raw TCP packet, not httpResponse
048: private static final boolean DEBUG_STATIC_PAGE_RAW = false;
049: // Allocate a new response for each response
050: private static final boolean DEBUG_STATIC_PAGE_ALLOCATE = false;
051: // If true, break up write of raw page into small chunks
052: private static final boolean DEBUG_STATIC_PAGE_RAW_MULTIWRITE = false;
053: private static final int DEBUG_multiWriteSize = 8192;
054:
055: // Send two different page sizes with fixed distribution
056: private static final boolean DEBUG_STATIC_PAGE_BIMODAL = false;
057: private static final int DEBUG_STATIC_PAGE_SIZE2 = 200;
058: private static final double DEBUG_bimodalSmallPageFreq = 0.1;
059:
060: // Send response based on size computed from SPECweb99 files
061: private static final boolean DEBUG_STATIC_PAGE_CLASS = false;
062: // Base sizes of files in each class
063: private static final int DEBUG_classBaseSize[] = { 1024, 10240,
064: 102400, 1024000 };
065: // Number of files per class
066: private static final int DEBUG_filesPerClass = 9;
067: // Max size of a file
068: private static final int DEBUG_maxClassFileSize = (DEBUG_classBaseSize[3] * DEBUG_filesPerClass) / 10;
069: private static int DEBUG_classFileSizes[][];
070: private static httpOKResponse DEBUG_classResps[][];
071:
072: private SinkIF sendSink;
073: private Random rand;
074:
075: private BufferElement static_page;
076: private httpOKResponse static_page_response;
077: private httpOKResponse static_page_response2;
078: private byte static_page_payload[];
079: private BufferElement static_page_raw_chunks[];
080:
081: static {
082: // Initialize DEBUG_classFileSizes
083: DEBUG_classFileSizes = new int[DEBUG_classBaseSize.length][];
084: for (int c = 0; c < DEBUG_classBaseSize.length; c++) {
085: DEBUG_classFileSizes[c] = new int[DEBUG_filesPerClass];
086: for (int n = 0; n < DEBUG_filesPerClass; n++) {
087: int sz = (DEBUG_classBaseSize[c] * (n + 1)) / 10;
088: DEBUG_classFileSizes[c][n] = sz;
089: }
090: }
091: }
092:
093: // Given a URL, return the size of the associated SPECweb99 file
094: public static int classURLToSize(String url) {
095: int cn = url.indexOf("class");
096: if (cn == -1) {
097: return 0;
098: }
099: int classnum = new Integer(url.substring(cn + 5, cn + 6))
100: .intValue();
101: int filenum = new Integer(url.substring(cn + 7, cn + 8))
102: .intValue();
103: // Limit to filesPerClass
104: filenum = Math.min(DEBUG_filesPerClass - 1, filenum);
105: return DEBUG_classFileSizes[classnum][filenum];
106: }
107:
108: public void init(ConfigDataIF config) throws Exception {
109: sendSink = config.getManager().getStage(HTTP_SEND_STAGE)
110: .getSink();
111: rand = new Random();
112:
113: if (DEBUG_STATIC_PAGE_RAW) {
114: ByteArrayOutputStream baos = new ByteArrayOutputStream();
115: PrintWriter pw = new PrintWriter(baos);
116: // Apache header
117: pw.println("HTTP/1.1 200 OK");
118: pw.println("Date: Fri, 20 Oct 2000 18:33:14 GMT");
119: pw
120: .println("Server: Apache/1.3.6 (Unix) (Red Hat/Linux) PHP/3.0.9");
121: pw.println("Last-Modified: Thu, 12 Oct 2000 19:39:35 GMT");
122: pw.println("ETag: \"5a80f-2000-39e61377\"");
123: pw.println("Accept-Ranges: bytes");
124: pw.println("Content-Length: " + DEBUG_STATIC_PAGE_SIZE);
125: pw.println("Content-Type: text/html\n");
126: pw.flush();
127: byte header[] = baos.toByteArray();
128: byte response[] = new byte[DEBUG_STATIC_PAGE_SIZE
129: + header.length];
130: System.arraycopy(header, 0, response, 0, header.length);
131: for (int i = header.length; i < DEBUG_STATIC_PAGE_SIZE
132: + header.length - 1; i++) {
133: response[i] = (byte) 'A';
134: }
135: response[DEBUG_STATIC_PAGE_SIZE + header.length - 1] = (byte) '\n';
136: static_page = new BufferElement(response);
137:
138: if (DEBUG_STATIC_PAGE_RAW_MULTIWRITE) {
139: int numChunks = response.length / DEBUG_multiWriteSize;
140: if ((response.length % DEBUG_multiWriteSize) != 0) {
141: numChunks++;
142: }
143: static_page_raw_chunks = new BufferElement[numChunks];
144: int off = 0;
145: for (int i = 0; i < numChunks; i++) {
146: int sz = Math.min(DEBUG_multiWriteSize,
147: (response.length - off));
148: static_page_raw_chunks[i] = new BufferElement(sz);
149: System.arraycopy(response, off,
150: static_page_raw_chunks[i].data, 0, sz);
151: off += sz;
152: }
153: }
154:
155: } else if (DEBUG_STATIC_PAGE_CLASS) {
156: DEBUG_classResps = new httpOKResponse[DEBUG_classBaseSize.length][];
157: for (int c = 0; c < DEBUG_classBaseSize.length; c++) {
158: DEBUG_classResps[c] = new httpOKResponse[DEBUG_filesPerClass];
159: for (int n = 0; n < DEBUG_filesPerClass; n++) {
160: int sz = (DEBUG_classBaseSize[c] * (n + 1)) / 10;
161: DEBUG_classResps[c][n] = new httpOKResponse(
162: "text/plain", sz);
163: }
164: }
165:
166: } else {
167: static_page_response = new httpOKResponse("text/plain",
168: DEBUG_STATIC_PAGE_SIZE);
169: static_page_payload = new byte[DEBUG_STATIC_PAGE_SIZE];
170: for (int i = 0; i < DEBUG_STATIC_PAGE_SIZE; i++) {
171: static_page_payload[i] = (byte) 'a';
172: }
173: BufferElement payload = static_page_response.getPayload();
174: byte paydata[] = payload.data;
175: System.arraycopy(static_page_payload, 0, paydata,
176: payload.offset, payload.size);
177:
178: if (DEBUG_STATIC_PAGE_BIMODAL) {
179: static_page_response2 = new httpOKResponse(
180: "text/plain", DEBUG_STATIC_PAGE_SIZE2);
181: byte static_page_payload2[] = new byte[DEBUG_STATIC_PAGE_SIZE2];
182: for (int i = 0; i < DEBUG_STATIC_PAGE_SIZE2; i++) {
183: static_page_payload2[i] = (byte) 'a';
184: }
185: payload = static_page_response2.getPayload();
186: paydata = payload.data;
187: System.arraycopy(static_page_payload2, 0, paydata,
188: payload.offset, payload.size);
189: }
190: }
191:
192: }
193:
194: public void destroy() {
195: }
196:
197: public void handleEvent(QueueElementIF item) {
198: if (DEBUG)
199: System.err.println("PageCache: GOT QEL: " + item);
200:
201: if (item instanceof httpRequest) {
202: HaboobStats.numRequests++;
203:
204: httpRequest req = (httpRequest) item;
205: if (req.getRequest() != httpRequest.REQUEST_GET) {
206: HaboobStats.numErrors++;
207: sendSink
208: .enqueue_lossy(new httpResponder(
209: new httpBadRequestResponse(req,
210: "Only GET requests supported at this time"),
211: req, true));
212: return;
213: }
214:
215: if (DEBUG_STATIC_PAGE_RAW) {
216: ATcpConnection atcpconn = req.getConnection()
217: .getConnection();
218:
219: if (DEBUG_STATIC_PAGE_RAW_MULTIWRITE) {
220: for (int i = 0; i < static_page_raw_chunks.length; i++) {
221: if (!atcpconn
222: .enqueue_lossy(static_page_raw_chunks[i])) {
223: System.err
224: .println("PageCache: Warning: Cannot enqueue_lossy static page "
225: + static_page);
226: }
227: }
228: } else {
229: if (!atcpconn.enqueue_lossy(static_page)) {
230: System.err
231: .println("PageCache: Warning: Cannot enqueue_lossy static page "
232: + static_page);
233: }
234: }
235:
236: } else if (DEBUG_STATIC_PAGE_CLASS) {
237: String url = req.getURL();
238: int cn = url.indexOf("class");
239: if (cn == -1) {
240: System.err.println("Got bad url: " + url);
241: return;
242: }
243: int classnum = new Integer(url
244: .substring(cn + 5, cn + 6)).intValue();
245: int filenum = new Integer(url.substring(cn + 7, cn + 8))
246: .intValue();
247: // Limit to filesPerClass
248: filenum = Math.min(DEBUG_filesPerClass - 1, filenum);
249: httpOKResponse res;
250:
251: if (DEBUG_STATIC_PAGE_ALLOCATE) {
252: int sz = DEBUG_classFileSizes[classnum][filenum];
253: res = new httpOKResponse("text/html", sz);
254: } else {
255: res = DEBUG_classResps[classnum][filenum];
256: }
257: if (DEBUG)
258: System.err.println("Got url " + url + ", class "
259: + classnum + ", filenum " + filenum
260: + ", sz " + res.getPayload().size);
261: httpResponder resp = new httpResponder(res, req);
262: if (!sendSink.enqueue_lossy(resp)) {
263: System.err
264: .println("PageCache: Warning: Cannot enqueue_lossy static page "
265: + resp);
266: }
267:
268: } else if (DEBUG_STATIC_PAGE_BIMODAL) {
269: boolean sendSmall = (rand.nextDouble() <= DEBUG_bimodalSmallPageFreq) ? (true)
270: : (false);
271: httpResponder resp;
272: if (sendSmall) {
273: resp = new httpResponder(static_page_response2, req);
274: } else {
275: resp = new httpResponder(static_page_response, req);
276: }
277: if (!sendSink.enqueue_lossy(resp)) {
278: System.err
279: .println("PageCache: Warning: Cannot enqueue_lossy static page "
280: + resp);
281: }
282:
283: } else {
284: // Just send static response
285:
286: httpResponder resp;
287: if (!DEBUG_STATIC_PAGE_ALLOCATE) {
288: resp = new httpResponder(static_page_response, req);
289: } else {
290: resp = new httpResponder(new httpOKResponse(
291: "text/html", DEBUG_STATIC_PAGE_SIZE), req);
292: }
293: if (!sendSink.enqueue_lossy(resp)) {
294: System.err
295: .println("PageCache: Warning: Cannot enqueue_lossy static page "
296: + resp);
297: }
298: }
299:
300: return;
301:
302: } else if (item instanceof SinkClosedEvent) {
303: // Ignore
304:
305: } else {
306: System.err.println("StaticPage: Got unknown event type: "
307: + item);
308: }
309:
310: }
311:
312: public void handleEvents(QueueElementIF items[]) {
313: for (int i = 0; i < items.length; i++) {
314: handleEvent(items[i]);
315: }
316: }
317:
318: }
|