/* * Copyright amoeba.meidusa.com * * This program is free software; you can redistribute it and/or modify it under the terms of * the GNU AFFERO GENERAL PUBLIC LICENSE as published by the Free Software Foundation; either version 3 of the License, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU AFFERO GENERAL PUBLIC LICENSE for more details. * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE along with this program; * if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package com.meidusa.amoeba.mongodb.handler; import java.util.ArrayList; import java.util.List; import org.bson.BSONObject; import com.meidusa.amoeba.context.ProxyRuntimeContext; import com.meidusa.amoeba.mongodb.handler.merge.FunctionMerge; import com.meidusa.amoeba.mongodb.io.MongodbPacketConstant; import com.meidusa.amoeba.mongodb.net.MongodbClientConnection; import com.meidusa.amoeba.mongodb.net.MongodbServerConnection; import com.meidusa.amoeba.mongodb.packet.CursorEntry; import com.meidusa.amoeba.mongodb.packet.MongodbPacketBuffer; import com.meidusa.amoeba.mongodb.packet.QueryMongodbPacket; import com.meidusa.amoeba.mongodb.packet.ResponseMongodbPacket; import com.meidusa.amoeba.mongodb.packet.SimpleResponseMongodbPacket; import com.meidusa.amoeba.mongodb.route.MongodbQueryRouter; import com.meidusa.amoeba.net.poolable.ObjectPool; import com.meidusa.amoeba.util.Tuple; public class QueryMessageHandler extends AbstractSessionHandler<QueryMongodbPacket> { private List<Tuple<CursorEntry,ObjectPool>> cursorList; public QueryMessageHandler(MongodbClientConnection clientConn,QueryMongodbPacket packet) { super(clientConn,packet); } @Override protected void doClientRequest(MongodbClientConnection conn, byte[] message) throws Exception { //request last error if(requestPacket.fullCollectionName.indexOf(".$cmd")>0){ if(requestPacket.query != null){ if(requestPacket.query.get("getlasterror") != null){ byte[] msg = clientConn.getLastErrorMessage(); ResponseMongodbPacket packet = new ResponseMongodbPacket(); if(msg == null){ packet.numberReturned = 1; packet.documents = new ArrayList<BSONObject>(1); packet.documents.add(BSON_OK); PACKET_LOGGER.error("cannot getLasterrorMessage with requst="+this.requestPacket); }else{ packet.init(msg, conn); } packet.numberReturned = 1; packet.responseTo = this.requestPacket.requestID; if(PACKET_LOGGER.isDebugEnabled()){ PACKET_LOGGER.debug("<<----@ReponsePacket="+packet+", " +clientConn.getSocketId()); } clientConn.postMessage(packet.toByteBuffer(conn)); return; }else{ if(requestPacket.query.get("group") != null){ this.cmd = MongodbPacketConstant.CMD_GROUP; }else if(requestPacket.query.get("count") != null){ this.cmd = MongodbPacketConstant.CMD_COUNT; }else if(requestPacket.query.get("drop") != null){ this.cmd = MongodbPacketConstant.CMD_DROP; }else if(requestPacket.query.get("distinct") != null){ this.cmd = MongodbPacketConstant.CMD_DISTINCT; }else if(requestPacket.query.get("deleteIndexes") != null){ this.cmd = MongodbPacketConstant.CMD_DROP_INDEXES; }else if(requestPacket.query.get("mapreduce") != null){ this.cmd = MongodbPacketConstant.CMD_MAP_REDUCE; }else if(requestPacket.query.get("listDatabases") != null){ this.cmd = MongodbPacketConstant.CMD_LISTDATABASES; }else if(requestPacket.query.get("$eval") != null){ Object object = requestPacket.query.get("$eval"); if(object instanceof BSONObject){ BSONObject bson = (BSONObject) object; for(String name : bson.keySet()){ if(name.startsWith("db.getSisterDB")){ this.cmd = MongodbPacketConstant.CMD_GETCOLLECTION; break; } } } } } } } //other request MongodbQueryRouter router = (MongodbQueryRouter)ProxyRuntimeContext.getInstance().getQueryRouter(); ObjectPool[] pools = router.doRoute(clientConn, requestPacket); if(pools == null || pools.length==0){ pools = router.getDefaultObjectPool(); } if(pools != null && pools.length >1){ isMulti = true; cursorList = new ArrayList<Tuple<CursorEntry,ObjectPool>>(); this.multiResponsePacket = new ArrayList<ResponseMongodbPacket>(); } MongodbServerConnection[] conns = new MongodbServerConnection[pools.length]; int index =0; for(ObjectPool pool: pools){ try{ MongodbServerConnection serverConn = (MongodbServerConnection)pool.borrowObject(); serverConn.setSessionMessageHandler(this); conns[index++] = serverConn; handlerMap.put(serverConn, serverConn.getMessageHandler()); }catch(Exception e){ handlerLogger.error("poolName=["+pool.getName()+"] borrow Connection error",e); } } if(index == 0){ throw new Exception("no pool to query,queryObject="+this.requestPacket); } for(MongodbServerConnection serverConn : conns){ if(serverConn != null){ serverConn.postMessage(message); } } } @Override protected void doServerResponse(MongodbServerConnection conn, byte[] message) { SimpleResponseMongodbPacket packet = null; MongodbServerConnection serverConn = (MongodbServerConnection) conn; int type = MongodbPacketBuffer.getOPMessageType(message); if(type != MongodbPacketConstant.OP_REPLY){ PACKET_LOGGER.error("unkown response packet type="+type+" , request="+this.requestPacket); } if(ROUTER_TRACE.isDebugEnabled() || isMulti){ packet = new ResponseMongodbPacket(); }else{ packet = new SimpleResponseMongodbPacket(); } packet.init(message, conn); if(PACKET_LOGGER.isDebugEnabled()){ PACKET_LOGGER.debug("<<---["+this.requestPacket.requestID+"]--pakcet="+packet+"," +conn.getSocketId()); } if(ROUTER_TRACE.isDebugEnabled()){ putDebugInfoToResponsePacket((ResponseMongodbPacket)packet,conn); } if(isMulti){ multiResponsePacket.add((ResponseMongodbPacket)packet); if(packet.cursorID >0){ CursorEntry entry = new CursorEntry(); entry.cursorID = packet.cursorID; entry.fullCollectionName = this.requestPacket.fullCollectionName; Tuple<CursorEntry,ObjectPool> tuple = new Tuple<CursorEntry,ObjectPool>(entry,serverConn.getObjectPool()); this.cursorList.add(tuple); } if(endQuery(conn)){ long cursrID = 0; if(cursorList.size()>=1){ cursrID = this.clientConn.nextCursorID(); clientConn.putCursor(cursrID, cursorList); } ResponseMongodbPacket result = null; if(this.cmd>0){ FunctionMerge merge = FUNCTION_MERGE_MAP.get(this.cmd); result = merge.mergeResponse(this.requestPacket, multiResponsePacket); }else{ if(this.requestPacket.fullCollectionName.indexOf("system.namespaces")>0){ //merge name spaces FunctionMerge merge = FUNCTION_MERGE_MAP.get(MongodbPacketConstant.CMD_NAMESPACES); result = merge.mergeResponse(requestPacket, multiResponsePacket); }else{ result = this.mergeResponse(this.requestPacket.numberToReturn == -1); } } result.cursorID = cursrID; clientConn.postMessage(result.toByteBuffer(this.clientConn)); } }else{ if(packet.cursorID >0){ CursorEntry entry = new CursorEntry(); entry.cursorID = packet.cursorID; entry.fullCollectionName = this.requestPacket.fullCollectionName; Tuple<CursorEntry,ObjectPool> tuple = new Tuple<CursorEntry,ObjectPool>(entry,serverConn.getObjectPool()); clientConn.addCursorItem(packet.cursorID, tuple); } endQuery(conn); if(ROUTER_TRACE.isDebugEnabled()){ clientConn.postMessage(packet.toByteBuffer(serverConn)); }else{ clientConn.postMessage(message); } } } }