001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.jk.common;
019:
020: import java.io.IOException;
021: import java.util.Vector;
022:
023: import org.apache.jk.apr.AprImpl;
024: import org.apache.jk.core.Msg;
025: import org.apache.jk.core.MsgContext;
026: import org.apache.jk.core.WorkerEnv;
027: import org.apache.tomcat.util.IntrospectionUtils;
028: import org.apache.tomcat.util.buf.C2BConverter;
029:
030: /* The code is a bit confusing at this moment - the class is used as
031: a Bean, or ant Task, or CLI - i.e. you set properties and call execute.
032:
033: That's different from the rest of jk handlers wich are stateless ( but
034: similar with Coyote-http ).
035: */
036:
037: /** Handle the shared memory objects.
038: *
039: * @author Costin Manolache
040: */
041: public class Shm extends JniHandler {
042: String file = "/tmp/shm.file";
043: int size;
044: String host = "localhost";
045: int port = 8009;
046: String unixSocket;
047:
048: boolean help = false;
049: boolean unregister = false;
050: boolean reset = false;
051: String dumpFile = null;
052:
053: Vector groups = new Vector();
054:
055: // Will be dynamic ( getMethodId() ) after things are stable
056: static final int SHM_WRITE_SLOT = 2;
057: static final int SHM_RESET = 5;
058: static final int SHM_DUMP = 6;
059:
060: public Shm() {
061: }
062:
063: /** Scoreboard location
064: */
065: public void setFile(String f) {
066: file = f;
067: }
068:
069: /** Copy the scoreboard in a file for debugging
070: * Will also log a lot of information about what's in the scoreboard.
071: */
072: public void setDump(String dumpFile) {
073: this .dumpFile = dumpFile;
074: }
075:
076: /** Size. Used only if the scoreboard is to be created.
077: */
078: public void setSize(int size) {
079: this .size = size;
080: }
081:
082: /** Set this to get the scoreboard reset.
083: * The shm segment will be destroyed and a new one created,
084: * with the provided size.
085: *
086: * Requires "file" and "size".
087: */
088: public void setReset(boolean b) {
089: reset = true;
090: }
091:
092: /** Ajp13 host
093: */
094: public void setHost(String host) {
095: this .host = host;
096: }
097:
098: /** Mark this instance as belonging to a group
099: */
100: public void setGroup(String grp) {
101: groups.addElement(grp);
102: }
103:
104: /** Ajp13 port
105: */
106: public void setPort(int port) {
107: this .port = port;
108: }
109:
110: /** Unix socket where tomcat is listening.
111: * Use it only if tomcat is on the same host, of course
112: */
113: public void setUnixSocket(String unixSocket) {
114: this .unixSocket = unixSocket;
115: }
116:
117: /** Set this option to mark the tomcat instance as
118: 'down', so apache will no longer forward messages to it.
119: Note that requests with a session will still try this
120: host first.
121:
122: This can be used to implement gracefull shutdown.
123:
124: Host and port are still required, since they are used
125: to identify tomcat.
126: */
127: public void setUnregister(boolean unregister) {
128: this .unregister = true;
129: }
130:
131: public void init() throws IOException {
132: super .initNative("shm");
133: if (apr == null)
134: return;
135: if (file == null) {
136: log.error("No shm file, disabling shared memory");
137: apr = null;
138: return;
139: }
140:
141: // Set properties and call init.
142: setNativeAttribute("file", file);
143: if (size > 0)
144: setNativeAttribute("size", Integer.toString(size));
145:
146: initJkComponent();
147: }
148:
149: public void resetScoreboard() throws IOException {
150: if (apr == null)
151: return;
152: MsgContext mCtx = createMsgContext();
153: Msg msg = (Msg) mCtx.getMsg(0);
154: msg.reset();
155:
156: msg.appendByte(SHM_RESET);
157:
158: this .invoke(msg, mCtx);
159: }
160:
161: public void dumpScoreboard(String fname) throws IOException {
162: if (apr == null)
163: return;
164: MsgContext mCtx = createMsgContext();
165: Msg msg = (Msg) mCtx.getMsg(0);
166: C2BConverter c2b = mCtx.getConverter();
167: msg.reset();
168:
169: msg.appendByte(SHM_DUMP);
170:
171: appendString(msg, fname, c2b);
172:
173: this .invoke(msg, mCtx);
174: }
175:
176: /** Register a tomcat instance
177: * XXX make it more flexible
178: */
179: public void registerTomcat(String host, int port, String unixDomain)
180: throws IOException {
181: String instanceId = host + ":" + port;
182:
183: String slotName = "TOMCAT:" + instanceId;
184: MsgContext mCtx = createMsgContext();
185: Msg msg = (Msg) mCtx.getMsg(0);
186: msg.reset();
187: C2BConverter c2b = mCtx.getConverter();
188:
189: msg.appendByte(SHM_WRITE_SLOT);
190: appendString(msg, slotName, c2b);
191:
192: int channelCnt = 1;
193: if (unixDomain != null)
194: channelCnt++;
195:
196: // number of groups. 0 means the default lb.
197: msg.appendInt(groups.size());
198: for (int i = 0; i < groups.size(); i++) {
199: appendString(msg, (String) groups.elementAt(i), c2b);
200: appendString(msg, instanceId, c2b);
201: }
202:
203: // number of channels for this instance
204: msg.appendInt(channelCnt);
205:
206: // The body:
207: appendString(msg, "channel.socket:" + host + ":" + port, c2b);
208: msg.appendInt(1);
209: appendString(msg, "tomcatId", c2b);
210: appendString(msg, instanceId, c2b);
211:
212: if (unixDomain != null) {
213: appendString(msg, "channel.apr:" + unixDomain, c2b);
214: msg.appendInt(1);
215: appendString(msg, "tomcatId", c2b);
216: appendString(msg, instanceId, c2b);
217: }
218:
219: if (log.isDebugEnabled())
220: log.debug("Register " + instanceId);
221: this .invoke(msg, mCtx);
222: }
223:
224: public void unRegisterTomcat(String host, int port)
225: throws IOException {
226: String slotName = "TOMCAT:" + host + ":" + port;
227: MsgContext mCtx = createMsgContext();
228: Msg msg = (Msg) mCtx.getMsg(0);
229: msg.reset();
230: C2BConverter c2b = mCtx.getConverter();
231:
232: msg.appendByte(SHM_WRITE_SLOT);
233: appendString(msg, slotName, c2b);
234:
235: // number of channels for this instance
236: msg.appendInt(0);
237: msg.appendInt(0);
238:
239: if (log.isDebugEnabled())
240: log.debug("UnRegister " + slotName);
241: this .invoke(msg, mCtx);
242: }
243:
244: public void destroy() throws IOException {
245: destroyJkComponent();
246: }
247:
248: public int invoke(Msg msg, MsgContext ep) throws IOException {
249: if (apr == null)
250: return 0;
251: log.debug("ChannelShm.invoke: " + ep);
252: super .nativeDispatch(msg, ep, JK_HANDLE_SHM_DISPATCH, 0);
253: return 0;
254: }
255:
256: private static org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory
257: .getLog(Shm.class);
258:
259: //-------------------- Main - use the shm functions from ant or CLI ------
260:
261: /** Local initialization - for standalone use
262: */
263: public void initCli() throws IOException {
264: WorkerEnv wEnv = new WorkerEnv();
265: AprImpl apr = new AprImpl();
266: wEnv.addHandler("apr", apr);
267: wEnv.addHandler("shm", this );
268: apr.init();
269: if (!apr.isLoaded()) {
270: log
271: .error("No native support. "
272: + "Make sure libapr.so and libjkjni.so are available in LD_LIBRARY_PATH");
273: return;
274: }
275: }
276:
277: public void execute() {
278: try {
279: if (help)
280: return;
281: initCli();
282: init();
283:
284: if (reset) {
285: resetScoreboard();
286: } else if (dumpFile != null) {
287: dumpScoreboard(dumpFile);
288: } else if (unregister) {
289: unRegisterTomcat(host, port);
290: } else {
291: registerTomcat(host, port, unixSocket);
292: }
293: } catch (Exception ex) {
294: log.error("Error executing Shm", ex);
295: }
296: }
297:
298: public void setHelp(boolean b) {
299: if (log.isDebugEnabled()) {
300: log.debug("Usage: ");
301: log.debug(" Shm [OPTIONS]");
302: log.debug("");
303: log.debug(" -file SHM_FILE");
304: log
305: .debug(" -group GROUP ( can be specified multiple times )");
306: log.debug(" -host HOST");
307: log.debug(" -port PORT");
308: log.debug(" -unixSocket UNIX_FILE");
309: // log.debug(" -priority XXX");
310: // log.debug(" -lbFactor XXX");
311: }
312: help = true;
313: return;
314: }
315:
316: public static void main(String args[]) {
317: try {
318: Shm shm = new Shm();
319:
320: if (args.length == 0 || ("-?".equals(args[0]))) {
321: shm.setHelp(true);
322: return;
323: }
324:
325: IntrospectionUtils.processArgs(shm, args);
326: shm.execute();
327: } catch (Exception ex) {
328: ex.printStackTrace();
329: }
330: }
331: }
|