/** * Creates a {@link Connection} with {@link Connection.Modality#Synchronous} semantics suitable * for use by synchronous (blocking) JRedis clients. * * <p>[TODO: this method should be using connection spec!] * * @param host * @param port * @param redisVersion * @return */ protected Connection createSynchConnection(String host, int port, RedisVersion redisVersion) { InetAddress address = null; Connection synchConnection = null; try { address = InetAddress.getByName(host); synchConnection = new SynchConnection(address, port, redisVersion); Assert.notNull(synchConnection, "connection delegate", ClientRuntimeException.class); } catch (NotSupportedException e) { Log.log("Can not support redis protocol '%s'", redisVersion); throw e; } catch (ProviderException e) { Log.bug("Couldn't create the handler delegate. => " + e.getLocalizedMessage()); throw e; } catch (ClientRuntimeException e) { String msg = e.getMessage() + "\nMake sure your server is running."; Log.error("Error creating connection -> " + e.getLocalizedMessage()); setConnection(new FaultedConnection(msg)); } catch (UnknownHostException e) { String msg = "Couldn't obtain InetAddress for " + host; Log.problem(msg + " => " + e.getLocalizedMessage()); throw new ClientRuntimeException(msg, e); } return synchConnection; }
/** * Keeps processing the {@link PendingRequest}s in the pending {@link Queue} until a QUIT is * encountered in the pending queue. Thread will stop after processing the QUIT response (which * is expected to be a {@link VirtualResponse}. * * <p>TODO: not entirely clear what is the best way to handle exceptions. * * <p>TODO: socket Reconnect in the context of pipelining is non-trivial, and maybe not even * practically possible. (e.g. request n is sent but pipe breaks on some m (m!=n) response. non * trivial. */ public void run() { Log.log("AsyncConnection processor thread <%s> started.", Thread.currentThread().getName()); /** Response handler thread specific protocol handler -- optimize fencing */ Protocol protocol = Assert.notNull( newProtocolHandler(), "the delegate protocol handler", ClientRuntimeException.class); PendingRequest pending = null; while (true) { try { pending = pendingQueue.take(); try { Request request = Assert.notNull( protocol.createRequest(pending.cmd, pending.args), "request object from handler", ProviderException.class); request.write(getOutputStream()); pending.response = protocol.createResponse(pending.cmd); pending.response.read(getInputStream()); pending.completion.signal(); if (pending.response.getStatus().isError()) { Log.error( "(Asynch) Error response for " + pending.cmd.code + " => " + pending.response.getStatus().message()); } } catch (ProviderException bug) { Log.error("ProviderException: " + bug.getLocalizedMessage()); bug.printStackTrace(); pending.setCRE(bug); } catch (ClientRuntimeException cre) { Log.error("ClientRuntimeException: " + cre.getLocalizedMessage()); cre.printStackTrace(); pending.setCRE(cre); } catch (RuntimeException e) { Log.error("Unexpected RuntimeException ", e); e.printStackTrace(); pending.setCRE( new ProviderException("Unexpected runtime exception in response handler")); pending.setResponse(null); break; } // redis (1.00) simply shutsdown connection even if pending responses // are expected, so quit is NOT sent. we simply close connection on this // end. if (pending.cmd == Command.QUIT) { AsyncConnection.this.disconnect(); break; } } catch (InterruptedException e1) { e1.printStackTrace(); } } Log.log("AsyncConnection processor thread <%s> stopped.", Thread.currentThread().getName()); }
public Response serviceRequest(Command cmd, byte[]... args) throws RedisException { /* if(start ==-1) start = System.currentTimeMillis(); */ if (!isConnected()) throw new NotConnectedException("Not connected!"); Request request = null; Response response = null; ResponseStatus status = null; try { // 1 - Request // try { request = Assert.notNull( protocolHandler.createRequest(cmd, args), "request object from handler", ProviderException.class); request.write(super.getOutputStream()); } catch (ProviderException bug) { throw bug; } catch (ClientRuntimeException problem) { Throwable rootProblem = problem.getCause(); if (null != rootProblem && rootProblem instanceof SocketException) { Log.log( "[TODO -- attempt reconnect] serviceRequest() -- " + "unrecovered %s in Request phase <Cmd: %s>", rootProblem, cmd.code); } throw problem; // TODO: reconnect here ... } catch (RuntimeException everythingelse) { String msg = "For <Cmd: " + cmd.code + "> Possible bug in provider code: " + everythingelse.getClass().getSimpleName() + " => " + everythingelse.getLocalizedMessage(); Log.error("serviceRequest() -- Request phase -- " + msg); throw new ProviderException(msg, everythingelse); } // 2 - Response // try { response = Assert.notNull( protocolHandler.createResponse(cmd), "response object from handler", ProviderException.class); response.read(super.getInputStream()); } catch (ProviderException bug) { throw bug; } catch (ClientRuntimeException problem) { Throwable rootProblem = problem.getCause(); if (null != rootProblem) { if (rootProblem instanceof SocketException) { Log.log( "[NET] [TODO (attempt reconnect?)] serviceRequest(%s) -- " + "problem in Response phase <rootProblem: %s>", cmd.code, rootProblem); } else if (rootProblem instanceof IOException) { Log.log( "[IO] [TODO (attempt reconnect?)] serviceRequest(%s) -- " + "problem in Response phase <rootProblem: %s>", cmd.code, rootProblem); } } throw problem; // this is caught below under ClientR.. } // 3 - Status // // sending response didn't cause any problems // check for redis errors // status = Assert.notNull( response.getStatus(), "status from response object", ProviderException.class); if (status.isError()) { // Log.error ("Request resulted in error: cmd: " + cmd.code + " " + status.message()); Log.error(cmd.code + " => " + status.message()); throw new RedisException(cmd, status.message()); } else if (status.code() == ResponseStatus.Code.CIAO) { // Log.log ("serviceRequest() -- Response status is CIAO."); // Log.log ("serviceRequest() -- closing connection ..."); disconnect(); } } catch (ProviderException bug) { Log.bug("serviceRequest() -- ProviderException: " + bug.getLocalizedMessage()); Log.log("serviceRequest() -- closing connection ..."); // now we must close the connection if we can disconnect(); throw bug; } catch (ClientRuntimeException problem) { Log.problem( "serviceRequest() -- Unrecovered ClientRuntimeException: " + problem.getLocalizedMessage()); Log.log("serviceRequest() -- closing connection ..."); // now we must close the connection if we can disconnect(); throw problem; } catch (RuntimeException surprise) { surprise.printStackTrace(); // TODO: Log.log it ... Log.bug( "serviceRequest() -- *unexpected* RuntimeException: " + surprise.getLocalizedMessage()); Log.log("serviceRequest() -- closing connection ..."); // now we must close the connection if we can disconnect(); throw new ClientRuntimeException( "unexpected runtime exeption: " + surprise.getLocalizedMessage(), surprise); } catch (Error disaster) { disaster.printStackTrace(); // TODO: Log.log it ... Log.bug( "serviceRequest() -- *unforseen* Java System Error: " + disaster.getLocalizedMessage()); Log.log("serviceRequest() -- closing connection ..."); // now we must close the connection if we can disconnect(); throw new ClientRuntimeException( "unexpected system error: " + disaster.getLocalizedMessage(), disaster); } finally { } /* - temp benchmarking request service throughput serviceCount ++; if(serviceCount > gate) { delta = System.currentTimeMillis() - start; start = System.currentTimeMillis(); throughput = (serviceCount * 1000) / (float) delta; System.out.format ("<%s> - %8.2f /sec | serviced %d requests at %d msecs\n", Thread.currentThread().getName(), throughput, serviceCount, delta ); serviceCount = 0; } */ return response; }