/** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ package org.apache.bookkeeper.proto; import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.protobuf.ByteString; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.apache.bookkeeper.auth.AuthProviderFactoryFactory; import org.apache.bookkeeper.auth.AuthToken; import org.apache.bookkeeper.bookie.Bookie; import org.apache.bookkeeper.conf.ServerConfiguration; import org.apache.bookkeeper.processor.RequestProcessor; import org.apache.bookkeeper.stats.OpStatsLogger; import org.apache.bookkeeper.stats.StatsLogger; import org.apache.bookkeeper.util.OrderedSafeExecutor; import org.jboss.netty.channel.Channel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static org.apache.bookkeeper.bookie.BookKeeperServerStats.ADD_ENTRY; import static org.apache.bookkeeper.bookie.BookKeeperServerStats.ADD_ENTRY_REQUEST; import static org.apache.bookkeeper.bookie.BookKeeperServerStats.READ_ENTRY; import static org.apache.bookkeeper.bookie.BookKeeperServerStats.READ_ENTRY_REQUEST; import static org.apache.bookkeeper.bookie.BookKeeperServerStats.WRITE_LAC; import static org.apache.bookkeeper.bookie.BookKeeperServerStats.READ_LAC; import static org.apache.bookkeeper.bookie.BookKeeperServerStats.GET_BOOKIE_INFO; public class BookieRequestProcessor implements RequestProcessor { private final static Logger LOG = LoggerFactory.getLogger(BookieRequestProcessor.class); /** * The server configuration. We use this for getting the number of add and read * worker threads. */ private final ServerConfiguration serverCfg; /** * This is the Bookie instance that is used to handle all read and write requests. */ final Bookie bookie; /** * The threadpool used to execute all read entry requests issued to this server. */ private final OrderedSafeExecutor readThreadPool; /** * The threadpool used to execute all add entry requests issued to this server. */ private final OrderedSafeExecutor writeThreadPool; // Expose Stats private final BKStats bkStats = BKStats.getInstance(); private final boolean statsEnabled; final OpStatsLogger addRequestStats; final OpStatsLogger addEntryStats; final OpStatsLogger readRequestStats; final OpStatsLogger readEntryStats; final OpStatsLogger writeLacStats; final OpStatsLogger readLacStats; final OpStatsLogger getBookieInfoStats; public BookieRequestProcessor(ServerConfiguration serverCfg, Bookie bookie, StatsLogger statsLogger) { this.serverCfg = serverCfg; this.bookie = bookie; this.readThreadPool = createExecutor(this.serverCfg.getNumReadWorkerThreads(), "BookieReadThread-" + serverCfg.getBookiePort()); this.writeThreadPool = createExecutor(this.serverCfg.getNumAddWorkerThreads(), "BookieWriteThread-" + serverCfg.getBookiePort()); // Expose Stats this.statsEnabled = serverCfg.isStatisticsEnabled(); this.addEntryStats = statsLogger.getOpStatsLogger(ADD_ENTRY); this.addRequestStats = statsLogger.getOpStatsLogger(ADD_ENTRY_REQUEST); this.readEntryStats = statsLogger.getOpStatsLogger(READ_ENTRY); this.readRequestStats = statsLogger.getOpStatsLogger(READ_ENTRY_REQUEST); this.writeLacStats = statsLogger.getOpStatsLogger(WRITE_LAC); this.readLacStats = statsLogger.getOpStatsLogger(READ_LAC); this.getBookieInfoStats = statsLogger.getOpStatsLogger(GET_BOOKIE_INFO); } @Override public void close() { shutdownExecutor(writeThreadPool); shutdownExecutor(readThreadPool); } private OrderedSafeExecutor createExecutor(int numThreads, String nameFormat) { if (numThreads <= 0) { return null; } else { return OrderedSafeExecutor.newBuilder().numThreads(numThreads).name(nameFormat).build(); } } private void shutdownExecutor(OrderedSafeExecutor service) { if (null != service) { service.shutdown(); } } @Override public void processRequest(Object msg, Channel c) { // If we can decode this packet as a Request protobuf packet, process // it as a version 3 packet. Else, just use the old protocol. if (msg instanceof BookkeeperProtocol.Request) { BookkeeperProtocol.Request r = (BookkeeperProtocol.Request) msg; BookkeeperProtocol.BKPacketHeader header = r.getHeader(); switch (header.getOperation()) { case ADD_ENTRY: processAddRequestV3(r, c); break; case READ_ENTRY: processReadRequestV3(r, c); break; case AUTH: LOG.info("Ignoring auth operation from client {}",c.getRemoteAddress()); BookkeeperProtocol.AuthMessage message = BookkeeperProtocol.AuthMessage .newBuilder() .setAuthPluginName(AuthProviderFactoryFactory.authenticationDisabledPluginName) .setPayload(ByteString.copyFrom(AuthToken.NULL.getData())) .build(); BookkeeperProtocol.Response.Builder authResponse = BookkeeperProtocol.Response.newBuilder().setHeader(r.getHeader()) .setStatus(BookkeeperProtocol.StatusCode.EOK) .setAuthResponse(message); c.write(authResponse.build()); break; case WRITE_LAC: processWriteLacRequestV3(r,c); break; case READ_LAC: processReadLacRequestV3(r,c); break; case GET_BOOKIE_INFO: processGetBookieInfoRequestV3(r,c); break; default: LOG.info("Unknown operation type {}", header.getOperation()); BookkeeperProtocol.Response.Builder response = BookkeeperProtocol.Response.newBuilder().setHeader(r.getHeader()) .setStatus(BookkeeperProtocol.StatusCode.EBADREQ); c.write(response.build()); if (statsEnabled) { bkStats.getOpStats(BKStats.STATS_UNKNOWN).incrementFailedOps(); } break; } } else { BookieProtocol.Request r = (BookieProtocol.Request) msg; // process packet switch (r.getOpCode()) { case BookieProtocol.ADDENTRY: processAddRequest(r, c); break; case BookieProtocol.READENTRY: processReadRequest(r, c); break; default: LOG.error("Unknown op type {}, sending error", r.getOpCode()); c.write(ResponseBuilder.buildErrorResponse(BookieProtocol.EBADREQ, r)); if (statsEnabled) { bkStats.getOpStats(BKStats.STATS_UNKNOWN).incrementFailedOps(); } break; } } } private void processAddRequestV3(final BookkeeperProtocol.Request r, final Channel c) { WriteEntryProcessorV3 write = new WriteEntryProcessorV3(r, c, this); if (null == writeThreadPool) { write.run(); } else { writeThreadPool.submitOrdered(r.getAddRequest().getLedgerId(), write); } } private void processReadRequestV3(final BookkeeperProtocol.Request r, final Channel c) { ReadEntryProcessorV3 read = new ReadEntryProcessorV3(r, c, this); if (null == readThreadPool) { read.run(); } else { readThreadPool.submitOrdered(r.getReadRequest().getLedgerId(), read); } } private void processWriteLacRequestV3(final BookkeeperProtocol.Request r, final Channel c) { WriteLacProcessorV3 writeLac = new WriteLacProcessorV3(r, c, this); if (null == writeThreadPool) { writeLac.run(); } else { writeThreadPool.submit(writeLac); } } private void processReadLacRequestV3(final BookkeeperProtocol.Request r, final Channel c) { ReadLacProcessorV3 readLac = new ReadLacProcessorV3(r, c, this); if (null == readThreadPool) { readLac.run(); } else { readThreadPool.submit(readLac); } } private void processGetBookieInfoRequestV3(final BookkeeperProtocol.Request r, final Channel c) { GetBookieInfoProcessorV3 getBookieInfo = new GetBookieInfoProcessorV3(r, c, this); if (null == readThreadPool) { getBookieInfo.run(); } else { readThreadPool.submit(getBookieInfo); } } private void processAddRequest(final BookieProtocol.Request r, final Channel c) { WriteEntryProcessor write = new WriteEntryProcessor(r, c, this); if (null == writeThreadPool) { write.run(); } else { writeThreadPool.submitOrdered(r.getLedgerId(), write); } } private void processReadRequest(final BookieProtocol.Request r, final Channel c) { ReadEntryProcessor read = new ReadEntryProcessor(r, c, this); if (null == readThreadPool) { read.run(); } else { readThreadPool.submitOrdered(r.getLedgerId(), read); } } }