xmemcached 1.2.6.2緊急發(fā)布(升級到1.2.6.1的朋友注意)
Posted on 2010-10-22 15:52 dennis 閱讀(4715) 評論(4) 編輯 收藏 所屬分類: java 、my open-source今年在閱讀某個項目源碼的時候看到DelayQueue的使用,xmemcached 1.2.6.1的重連任務(wù)也是采用DelayQueue管理,ReconnectRequest實現(xiàn)Delayed接口,我突然想起去review下xmc的源碼,發(fā)現(xiàn)一個嚴(yán)重的BUG,原始代碼如下:
public final class ReconnectRequest implements Delayed {
public long getDelay(TimeUnit unit) {
return nextReconnectTimestamp - System.currentTimeMillis();
}
}
public long getDelay(TimeUnit unit) {
return nextReconnectTimestamp - System.currentTimeMillis();
}
}
getDelay返回該任務(wù)還剩下多少時間可以被執(zhí)行,將下次執(zhí)行的時間戳減去當(dāng)前時間即可,問題在于這里返回的是毫秒,而沒有調(diào)用getDelay傳入的TimeUnit做轉(zhuǎn)換,在DelayQueue內(nèi)部其實是用納秒做單位交給Condition對象去等待
for (;;) {
E first = q.peek();
if (first == null) {
available.await();
} else {
long delay = first.getDelay(TimeUnit.NANOSECONDS);
if (delay > 0) {
long tl = available.awaitNanos(delay);
} else {
E x = q.poll();
assert x != null;
if (q.size() != 0)
available.signalAll(); // wake up other takers
return x;
}
}
}
E first = q.peek();
if (first == null) {
available.await();
} else {
long delay = first.getDelay(TimeUnit.NANOSECONDS);
if (delay > 0) {
long tl = available.awaitNanos(delay);
} else {
E x = q.poll();
assert x != null;
if (q.size() != 0)
available.signalAll(); // wake up other takers
return x;
}
}
}
最終導(dǎo)致的問題是,awaitNanos很快返回(awaitNanos接受的是納秒,這里卻傳入毫秒),循環(huán)執(zhí)行發(fā)現(xiàn)重新計算的delay仍然大于0,循環(huán)等到getDelay返回的越來越小直到0才執(zhí)行相應(yīng)的Task,,造成的現(xiàn)象是在重連的時候cpu占用率很高。
單元測試的時候沒有發(fā)現(xiàn)這個問題,主要是因為功能正常,沒有關(guān)注資源消耗情況,因此慚愧地忽略了。
解決的辦法很簡單,修改getDelay方法即可:
public long getDelay(TimeUnit unit) {
return unit.convert(
nextReconnectTimestamp - System.currentTimeMillis(),
TimeUnit.MILLISECONDS);
}
return unit.convert(
nextReconnectTimestamp - System.currentTimeMillis(),
TimeUnit.MILLISECONDS);
}
這個BUG比較嚴(yán)重,已經(jīng)升級1.2.6.1的朋友建議馬上升級到1.2.6.2,使用maven的朋友只要修改版本即可,沒有使用maven的請到這里下載。