public void destroy() { super.destroy(); try { expireFuture.cancel(true); } catch (Throwable t) { logger.warn(t.getMessage(), t); } try { for (RedisRegistryNotifier notifier : notifiers.values()) { notifier.shutdown(); } } catch (Throwable t) { logger.warn(t.getMessage(), t); } for (Map.Entry<String, JedisPool> entry : jedisPools.entrySet()) { JedisPool jedisPool = entry.getValue(); try { jedisPool.destroy(); } catch (Throwable t) { logger.warn( "Failed to destroy the redis registry client. registry: " + entry.getKey() + ", cause: " + t.getMessage(), t); } } }
public void destroy() { if (logger.isInfoEnabled()) { logger.info("Destroy registry:" + getUrl()); } Set<URL> destroyRegistered = new HashSet<URL>(getRegistered()); if (!destroyRegistered.isEmpty()) { for (URL url : new HashSet<URL>(getRegistered())) { if (url.getParameter(Constants.DYNAMIC_KEY, true)) { try { unregister(url); if (logger.isInfoEnabled()) { logger.info("Destroy unregister url " + url); } } catch (Throwable t) { logger.warn( "Failed to unregister url " + url + " to registry " + getUrl() + " on destroy, cause: " + t.getMessage(), t); } } } } Map<URL, Set<NotifyListener>> destroySubscribed = new HashMap<URL, Set<NotifyListener>>(getSubscribed()); if (!destroySubscribed.isEmpty()) { for (Map.Entry<URL, Set<NotifyListener>> entry : destroySubscribed.entrySet()) { URL url = entry.getKey(); for (NotifyListener listener : entry.getValue()) { try { unsubscribe(url, listener); if (logger.isInfoEnabled()) { logger.info("Destroy unsubscribe url " + url); } } catch (Throwable t) { logger.warn( "Failed to unsubscribe url " + url + " to registry " + getUrl() + " on destroy, cause: " + t.getMessage(), t); } } } } }
protected Object decode(Channel channel, ChannelBuffer buffer, int readable, byte[] header) throws IOException { // check magic number. if (readable > 0 && header[0] != MAGIC_HIGH || readable > 1 && header[1] != MAGIC_LOW) { int length = header.length; if (header.length < readable) { header = Bytes.copyOf(header, readable); buffer.readBytes(header, length, readable - length); } for (int i = 1; i < header.length - 1; i++) { if (header[i] == MAGIC_HIGH && header[i + 1] == MAGIC_LOW) { buffer.readerIndex(buffer.readerIndex() - header.length + i); header = Bytes.copyOf(header, i); break; } } return super.decode(channel, buffer, readable, header); } // check length. if (readable < HEADER_LENGTH) { return DecodeResult.NEED_MORE_INPUT; } // get data length. int len = Bytes.bytes2int(header, 12); checkPayload(channel, len); int tt = len + HEADER_LENGTH; if (readable < tt) { return DecodeResult.NEED_MORE_INPUT; } // limit input stream. ChannelBufferInputStream is = new ChannelBufferInputStream(buffer, len); try { return decodeBody(channel, is, header); } finally { if (is.available() > 0) { try { if (logger.isWarnEnabled()) { logger.warn("Skip input stream " + is.available()); } StreamUtils.skipUnusedStream(is); } catch (IOException e) { logger.warn(e.getMessage(), e); } } } }
private void saveProperties(URL url) { if (file == null) { return; } try { StringBuilder buf = new StringBuilder(); Map<String, List<URL>> categoryNotified = notified.get(url); if (categoryNotified != null) { for (List<URL> us : categoryNotified.values()) { for (URL u : us) { if (buf.length() > 0) { buf.append(URL_SEPARATOR); } buf.append(u.toFullString()); } } } properties.setProperty(url.getServiceKey(), buf.toString()); long version = lastCacheChanged.incrementAndGet(); if (syncSaveFile) { doSaveProperties(version); } else { registryCacheExecutor.execute(new SaveProperties(version)); } } catch (Throwable t) { logger.warn(t.getMessage(), t); } }
private void deferExpired() { for (Map.Entry<String, JedisPool> entry : jedisPools.entrySet()) { JedisPool jedisPool = entry.getValue(); try { Jedis jedis = jedisPool.getResource(); try { RedisRegistryUtil.publishToJedis(jedis, getRegistered(), root, expirePeriod); if (admin) { clean(jedis); } if (!replicate) { break; // 如果服务器端已同步数据,只需写入单台机器 } } finally { jedisPool.returnResource(jedis); } } catch (Throwable t) { logger.warn( "Failed to write provider heartbeat to redis registry. registry: " + entry.getKey() + ", cause: " + t.getMessage(), t); } } }
public void doSubscribe(final URL url, final NotifyListener listener) { String service = RedisRegistryUtil.toServicePath(url, root); RedisRegistryNotifier notifier = notifiers.get(service); if (notifier == null) { RedisRegistryNotifier newNotifier = new RedisRegistryNotifier(service, this); notifiers.putIfAbsent(service, newNotifier); notifier = notifiers.get(service); if (notifier == newNotifier) { notifier.start(); } } boolean success = false; RpcException exception = null; for (Map.Entry<String, JedisPool> entry : jedisPools.entrySet()) { JedisPool jedisPool = entry.getValue(); try { Jedis jedis = jedisPool.getResource(); try { if (service.endsWith(Constants.ANY_VALUE)) { admin = true; Set<String> keys = jedis.keys(service); if (keys != null && keys.size() > 0) { Map<String, Set<String>> serviceKeys = RedisRegistryUtil.getServiceKeys(keys, root); for (Set<String> sk : serviceKeys.values()) { doNotify(jedis, sk, url, Arrays.asList(listener)); } } } else { doNotify( jedis, jedis.keys(service + Constants.PATH_SEPARATOR + Constants.ANY_VALUE), url, Arrays.asList(listener)); } success = true; break; // 只需读一个服务器的数据 } finally { jedisPool.returnResource(jedis); } } catch (Throwable t) { // 尝试下一个服务器 exception = new RpcException( "Failed to subscribe service from redis registry. registry: " + entry.getKey() + ", service: " + url + ", cause: " + t.getMessage(), t); } } if (exception != null) { if (success) { logger.warn(exception.getMessage(), exception); } else { throw exception; } } }
public static void warn(Logger logger, Throwable e) { if (logger == null) { return; } if (logger.isWarnEnabled()) { logger.warn(e); } }
public static void warn(Logger logger, String msg) { if (logger == null) { return; } if (logger.isWarnEnabled()) { logger.warn(msg); } }
public void close() { try { if (executor instanceof ExecutorService) { ((ExecutorService) executor).shutdown(); } } catch (Throwable t) { logger.warn("fail to destroy thread pool of server: " + t.getMessage(), t); } }
@Override protected void doClose() throws Throwable { try { if (acceptor != null) { acceptor.unbind(getBindAddress()); } } catch (Throwable e) { logger.warn(e.getMessage(), e); } }
private void loadProperties() { if (file != null && file.exists()) { InputStream in = null; try { in = new FileInputStream(file); properties.load(in); if (logger.isInfoEnabled()) { logger.info("Load registry store file " + file + ", data: " + properties); } } catch (Throwable e) { logger.warn("Failed to load registry store file " + file, e); } finally { if (in != null) { try { in.close(); } catch (IOException e) { logger.warn(e.getMessage(), e); } } } } }
protected void notify(URL url, NotifyListener listener, List<URL> urls) { if (url == null) { throw new IllegalArgumentException("notify url == null"); } if (listener == null) { throw new IllegalArgumentException("notify listener == null"); } if ((urls == null || urls.size() == 0) && !Constants.ANY_VALUE.equals(url.getServiceInterface())) { logger.warn("Ignore empty notify urls for subscribe url " + url); return; } if (logger.isInfoEnabled()) { logger.info("Notify urls for subscribe url " + url + ", urls: " + urls); } Map<String, List<URL>> result = new HashMap<String, List<URL>>(); for (URL u : urls) { if (UrlUtils.isMatch(url, u)) { String category = u.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY); List<URL> categoryList = result.get(category); if (categoryList == null) { categoryList = new ArrayList<URL>(); result.put(category, categoryList); } categoryList.add(u); } } if (result.size() == 0) { return; } Map<String, List<URL>> categoryNotified = notified.get(url); if (categoryNotified == null) { notified.putIfAbsent(url, new ConcurrentHashMap<String, List<URL>>()); categoryNotified = notified.get(url); } for (Map.Entry<String, List<URL>> entry : result.entrySet()) { String category = entry.getKey(); List<URL> categoryList = entry.getValue(); categoryNotified.put(category, categoryList); saveProperties(url); listener.notify(categoryList); } }
private void doNotify( Jedis jedis, Collection<String> keys, URL url, Collection<NotifyListener> listeners) { if (keys == null || keys.size() == 0 || listeners == null || listeners.size() == 0) { return; } long now = System.currentTimeMillis(); List<URL> result = new ArrayList<URL>(); List<String> categories = Arrays.asList(url.getParameter(Constants.CATEGORY_KEY, new String[0])); String consumerService = url.getServiceInterface(); for (String key : keys) { if (!Constants.ANY_VALUE.equals(consumerService)) { String prvoiderService = RedisRegistryUtil.toServiceName(key, root); if (!prvoiderService.equals(consumerService)) { continue; } } String category = RedisRegistryUtil.toCategoryName(key); if (!categories.contains(Constants.ANY_VALUE) && !categories.contains(category)) { continue; } Map<String, String> values = jedis.hgetAll(key); List<URL> urls = RedisRegistryUtil.getUrlsForDoNotify(url, now, values); if (urls.isEmpty()) { urls.add(RedisRegistryUtil.setUrlProperties(url, key, category, root)); } result.addAll(urls); if (logger.isWarnEnabled()) { logger.warn("redis notify: " + key + " = " + urls); } } if (result == null || result.size() == 0) { return; } for (NotifyListener listener : listeners) { notify(url, listener, result); } }
public void doRegister(URL url) { String key = RedisRegistryUtil.toCategoryPath(url, root); String value = url.toFullString(); String expire = String.valueOf(System.currentTimeMillis() + expirePeriod); boolean success = false; RpcException exception = null; for (Map.Entry<String, JedisPool> entry : jedisPools.entrySet()) { JedisPool jedisPool = entry.getValue(); try { Jedis jedis = jedisPool.getResource(); try { jedis.hset(key, value, expire); jedis.publish(key, Constants.REGISTER); success = true; if (!replicate) { break; // 如果服务器端已同步数据,只需写入单台机器 } } finally { jedisPool.returnResource(jedis); } } catch (Throwable t) { exception = new RpcException( "Failed to register service to redis registry. registry: " + entry.getKey() + ", service: " + url + ", cause: " + t.getMessage(), t); } } if (exception != null) { if (success) { logger.warn(exception.getMessage(), exception); } else { throw exception; } } }
public void doSaveProperties(long version) { if (version < lastCacheChanged.get()) { return; } if (file == null) { return; } Properties newProperties = new Properties(); // 保存之前先读取一遍,防止多个注册中心之间冲突 InputStream in = null; try { if (file.exists()) { in = new FileInputStream(file); newProperties.load(in); } } catch (Throwable e) { logger.warn("Failed to load registry store file, cause: " + e.getMessage(), e); } finally { if (in != null) { try { in.close(); } catch (IOException e) { logger.warn(e.getMessage(), e); } } } // 保存 try { newProperties.putAll(properties); File lockfile = new File(file.getAbsolutePath() + ".lock"); if (!lockfile.exists()) { lockfile.createNewFile(); } RandomAccessFile raf = new RandomAccessFile(lockfile, "rw"); try { FileChannel channel = raf.getChannel(); try { FileLock lock = channel.tryLock(); if (lock == null) { throw new IOException( "Can not lock the registry cache file " + file.getAbsolutePath() + ", ignore and retry later, maybe multi java process use the file, please config: dubbo.registry.file=xxx.properties"); } // 保存 try { if (!file.exists()) { file.createNewFile(); } FileOutputStream outputFile = new FileOutputStream(file); try { newProperties.store(outputFile, "Dubbo Registry Cache"); } finally { outputFile.close(); } } finally { lock.release(); } } finally { channel.close(); } } finally { raf.close(); } } catch (Throwable e) { if (version < lastCacheChanged.get()) { return; } else { registryCacheExecutor.execute(new SaveProperties(lastCacheChanged.incrementAndGet())); } logger.warn("Failed to save registry store file, cause: " + e.getMessage(), e); } }
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { String generic = invoker.getUrl().getParameter(Constants.GENERIC_KEY); if (ProtocolUtils.isGeneric(generic) && !Constants.$INVOKE.equals(invocation.getMethodName()) && invocation instanceof RpcInvocation) { RpcInvocation invocation2 = (RpcInvocation) invocation; String methodName = invocation2.getMethodName(); Class<?>[] parameterTypes = invocation2.getParameterTypes(); Object[] arguments = invocation2.getArguments(); String[] types = new String[parameterTypes.length]; for (int i = 0; i < parameterTypes.length; i++) { types[i] = ReflectUtils.getName(parameterTypes[i]); } Object[] args = PojoUtils.generalize(arguments); invocation2.setMethodName(Constants.$INVOKE); invocation2.setParameterTypes(GENERIC_PARAMETER_TYPES); invocation2.setArguments(new Object[] {methodName, types, args}); Result result = invoker.invoke(invocation2); if (!result.hasException()) { Object value = result.getValue(); try { Method method = invoker.getInterface().getMethod(methodName, parameterTypes); return new RpcResult( PojoUtils.realize(value, method.getReturnType(), method.getGenericReturnType())); } catch (NoSuchMethodException e) { throw new RpcException(e.getMessage(), e); } } else if (result.getException() instanceof GenericException) { GenericException exception = (GenericException) result.getException(); try { String className = exception.getExceptionClass(); Class<?> clazz = ReflectUtils.forName(className); Throwable targetException = null; Throwable lastException = null; try { targetException = (Throwable) clazz.newInstance(); } catch (Throwable e) { lastException = e; for (Constructor<?> constructor : clazz.getConstructors()) { try { targetException = (Throwable) constructor.newInstance(new Object[constructor.getParameterTypes().length]); break; } catch (Throwable e1) { lastException = e1; } } } if (targetException != null) { try { Field field = Throwable.class.getDeclaredField("detailMessage"); if (!field.isAccessible()) { field.setAccessible(true); } field.set(targetException, exception.getExceptionMessage()); } catch (Throwable e) { logger.warn(e.getMessage(), e); } result = new RpcResult(targetException); } else if (lastException != null) { throw lastException; } } catch (Throwable e) { throw new RpcException( "Can not deserialize exception " + exception.getExceptionClass() + ", message: " + exception.getExceptionMessage(), e); } } return result; } if (invocation.getMethodName().equals(Constants.$INVOKE) && invocation.getArguments() != null && invocation.getArguments().length == 3 && ProtocolUtils.isGeneric(generic)) { if (ProtocolUtils.isJavaGenericSerialization(generic)) { Object[] args = (Object[]) invocation.getArguments()[2]; for (Object arg : args) { if (!(byte[].class == arg.getClass())) { error(arg.getClass().getName()); } } } ((RpcInvocation) invocation) .setAttachment( Constants.GENERIC_KEY, invoker.getUrl().getParameter(Constants.GENERIC_KEY)); } return invoker.invoke(invocation); }
protected void encodeResponse(Channel channel, ChannelBuffer buffer, Response res) throws IOException { try { Serialization serialization = getSerialization(channel); // header. byte[] header = new byte[HEADER_LENGTH]; // set magic number. Bytes.short2bytes(MAGIC, header); // set request and serialization flag. header[2] = serialization.getContentTypeId(); if (res.isHeartbeat()) header[2] |= FLAG_EVENT; // set response status. byte status = res.getStatus(); header[3] = status; // set request id. Bytes.long2bytes(res.getId(), header, 4); int savedWriteIndex = buffer.writerIndex(); buffer.writerIndex(savedWriteIndex + HEADER_LENGTH); ChannelBufferOutputStream bos = new ChannelBufferOutputStream(buffer); ObjectOutput out = serialization.serialize(channel.getUrl(), bos); try { // encode response data or error message. if (status == Response.OK) { if (res.isHeartbeat()) { encodeHeartbeatData(channel, out, res.getResult()); } else { encodeResponseData(channel, out, res.getResult()); } } else out.writeUTF(res.getErrorMessage()); out.flushBuffer(); } finally { // modified by lishen if (out instanceof Cleanable) { ((Cleanable) out).cleanup(); } } bos.flush(); bos.close(); int len = bos.writtenBytes(); checkPayload(channel, len); Bytes.int2bytes(len, header, 12); // write buffer.writerIndex(savedWriteIndex); buffer.writeBytes(header); // write header. buffer.writerIndex(savedWriteIndex + HEADER_LENGTH + len); } catch (Throwable t) { // 发送失败信息给Consumer,否则Consumer只能等超时了 if (!res.isEvent() && res.getStatus() != Response.BAD_RESPONSE) { try { // FIXME 在Codec中打印出错日志?在IoHanndler的caught中统一处理? logger.warn( "Fail to encode response: " + res + ", send bad_response info instead, cause: " + t.getMessage(), t); Response r = new Response(res.getId(), res.getVersion()); r.setStatus(Response.BAD_RESPONSE); r.setErrorMessage( "Failed to send response: " + res + ", cause: " + StringUtils.toString(t)); channel.send(r); return; } catch (RemotingException e) { logger.warn( "Failed to send bad_response info back: " + res + ", cause: " + e.getMessage(), e); } } // 重新抛出收到的异常 if (t instanceof IOException) { throw (IOException) t; } else if (t instanceof RuntimeException) { throw (RuntimeException) t; } else if (t instanceof Error) { throw (Error) t; } else { throw new RuntimeException(t.getMessage(), t); } } }