@Override
  public synchronized void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)
      throws Exception {
    channel = ctx.getChannel();

    List<Command<K, V, ?>> tmp = new ArrayList<Command<K, V, ?>>(queue.size() + 2);

    if (password != null) {
      CommandArgs<K, V> args = new CommandArgs<K, V>(codec).add(password);
      tmp.add(new Command<K, V, String>(AUTH, new StatusOutput<K, V>(codec), args, false));
    }

    if (db != 0) {
      CommandArgs<K, V> args = new CommandArgs<K, V>(codec).add(db);
      tmp.add(new Command<K, V, String>(SELECT, new StatusOutput<K, V>(codec), args, false));
    }

    tmp.addAll(queue);
    queue.clear();

    for (Command<K, V, ?> cmd : tmp) {
      if (!cmd.isCancelled()) {
        queue.add(cmd);
        channel.write(cmd);
      }
    }

    tmp.clear();
  }
 public <T> T await(Command<K, V, T> cmd, long timeout, TimeUnit unit) {
   if (!cmd.await(timeout, unit)) {
     cmd.cancel(true);
     throw new RedisException("Command timed out");
   }
   CommandOutput<K, V, T> output = cmd.getOutput();
   if (output.hasError()) throw new RedisException(output.getError());
   return output.get();
 }
 @Override
 public synchronized void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e)
     throws Exception {
   if (closed) {
     for (Command<K, V, ?> cmd : queue) {
       cmd.getOutput().setError("Connection closed");
       cmd.complete();
     }
     queue.clear();
     queue = null;
     channel = null;
   }
 }