FEATURE: Support long type expiration time in v2 APIs#1101
Conversation
속성 타입 구조 정리 (as-is → to-be)
AS-IS (기존)v1은 한 클래스 계열(
TO-BE (변경 후)v1은 그대로 두고, v2는 역할별로 분리 + [v1 — 변경 X]
[v2 — 신규, long]
역할 분리 요약
|
oliviarla
left a comment
There was a problem hiding this comment.
다음은 클래스명 제안인데, @jhpark816 님도 함께 고민해주시면 좋겠습니다.
AttributeClause -> AttributesIF
AttributesCreate -> CreateAttrs
AttributesUpdate -> UpdateAttrs
AttributeResult -> Attrs (v2 인터페이스에서 getAttrs, setAttrs 메서드를 제공하는 가정 하)
지금은 인자명, 변수명이 제각각인데 클래스명이 결정된 후에 변수명을 하나로 통일하면 될 것 같습니다.
질문을 먼저 합니다.
|
966c773 to
df3b226
Compare
인터페이스와 구현 코드 첨부합니다. v2 - setAttributes API AsyncArcusCommandsIF.java /**
* Set the attributes of the item stored at the given key.
*
* @param key the key
* @param attributes the attributes to set
* @return {@code true} if the attributes were set, otherwise {@code false}
*/
ArcusFuture<Boolean> setAttributes(String key, AttributesUpdate attributes);AsyncArcusCommands.java @Override
public ArcusFuture<Boolean> setAttributes(String key, AttributesUpdate attributes) {
AbstractArcusResult<Boolean> result = new AbstractArcusResult<>(new AtomicReference<>());
ArcusFutureImpl<Boolean> future = new ArcusFutureImpl<>(result);
ArcusClient client = arcusClientSupplier.get();
OperationCallback cb = new OperationCallback() {
@Override
public void receivedStatus(OperationStatus status) {
switch (status.getStatusCode()) {
case SUCCESS:
result.set(true);
break;
case ERR_NOT_FOUND:
result.set(false);
break;
case CANCELLED:
future.internalCancel();
break;
default:
/*
* ATTR_ERROR or unknown statement.
*/
result.addError(key, status);
}
}
@Override
public void complete() {
future.complete();
}
};
Operation op = client.getOpFact().setAttr(key, attributes, cb);
future.setOp(op);
client.addOp(key, op);
return future;
}v2 - getAttributes API AsyncArcusCommandsIF.java /**
* Get the attributes of the item stored at the given key.
*
* @param key the key
* @return the {@link AttributesResult} of the item, or {@code null} if not found
*/
ArcusFuture<AttributesResult> getAttributes(String key);AsyncArcusCommands.java @Override
public ArcusFuture<AttributesResult> getAttributes(String key) {
keyValidator.validateKey(key);
AbstractArcusResult<AttributesResult> result =
new AbstractArcusResult<>(new AtomicReference<>());
ArcusFutureImpl<AttributesResult> future = new ArcusFutureImpl<>(result);
ArcusClient client = arcusClientSupplier.get();
AttributesResult attributes = new AttributesResult();
GetAttrOperation.Callback cb = new GetAttrOperation.Callback() {
@Override
public void gotAttribute(String key, String attr) {
attributes.setAttribute(attr);
}
@Override
public void receivedStatus(OperationStatus status) {
switch (status.getStatusCode()) {
case SUCCESS:
result.set(attributes);
break;
case ERR_NOT_FOUND:
result.set(null);
break;
case CANCELLED:
future.internalCancel();
break;
default:
/*
* ATTR_ERROR or unknown statement.
*/
result.addError(key, status);
}
}
@Override
public void complete() {
future.complete();
}
};
GetAttrOperation op = client.getOpFact().getAttr(key, cb);
future.setOp(op);
client.addOp(key, op);
return future;
} |
df3b226 to
dfb9f74
Compare
|
Attr 관련 클래스 분할, 사용 용도는 확인해 보니 OK입니다.
두 사람이 먼저 합의해 볼 수 있나요? |
|
현재 public interface SetAttrClause {
String stringify();
int getLength();
}기존 구조에서는 SetAttrOperationImpl
-> setArguments(..., attrs)
-> String.valueOf(attrs)
-> attrs.toString()즉, setattr 명령 문자열 생성이 다만 따라서 아래처럼 // as-is
setArguments(bb, "setattr", key, attrs);
// to-be
setArguments(bb, "setattr", key, attrs.stringify());정리하면, |
|
@f1v3-dev stringify() 메서드를 추가하는 것은 좋네요. |
AI에게 물어본 결과는 아래와 같고, 아래 용어가 괜찮은 것 같습니다.
앞서 민경 전임의 제안과 유사한데, |
다만 현재 해당 인터페이스의 역할이 관례만 놓고 보면 인터페이스명에는 |
|
CreateAttributes도 implement 해야 하는 interface이죠? |
CreateAttributes는 사용하지 않는 interface입니다.
|
클래스명을 해당 네이밍으로 변경하도록 하겠습니다. |
dfb9f74 to
b7041ab
Compare
|
해당 PR 이후 아래의 작업 이어서 진행하겠습니다.
|
OK. |
네 맞습니다.
다만, 현재 구조에서는 create / insert-with-create의 경우 해당 로직을 문자열(Clause) 생성 위치
|
|
@f1v3-dev |
public interface SetAttrOperation extends KeyedOperation {
SetAttrClause getAttributes();
}이 인터페이스를 보니 어색해 보이기 때문에, 말씀해주신대로 수정하도록 하겠습니다. |
b7041ab to
bda88de
Compare
bda88de to
45290c1
Compare
jhpark816
left a comment
There was a problem hiding this comment.
리뷰 완료
코드를 대략 보고 리뷰 의견을 남깁니다.
|
|
||
| public int getExpiration() { | ||
| return exp; | ||
| } |
There was a problem hiding this comment.
getExpiration() 메서드를 제거해도 되나요?
There was a problem hiding this comment.
get-and-touch 기능을 구현하면서 만들어진 메서드이나, 사용하지 않는 메서드여서 삭제를 해둔 상태입니다.
There was a problem hiding this comment.
@f1v3-dev
get-and-touch에서 touch 작업은 exp 재설정하는 작업입니다.
따라서, exp 값을 얻어오는 getExpiration() 메서드가 사용되어야 할 것 같은 데,
현재 구현에서 exp 값을 직접 접근하는 방식으로 되어 있는가 보죠?
There was a problem hiding this comment.
현재 구현에서 exp 값을 직접 접근하는 방식으로 되어 있는가 보죠?
맞습니다. 내부 필드 변수이기 때문에 직접 접근하는 방식으로 사용합니다.
아래는 직접적으로 사용하는 유일한 케이스입니다.
@Override
public final void initialize() {
int size;
StringBuilder commandBuilder = new StringBuilder();
byte[] commandLine;
ByteBuffer bb;
String keysString = generateKeysString();
switch (cmd) {
case "get":
case "gets":
// syntax: get || gets <keys...>\r\n
// ...
case "gat":
case "gats":
// syntax: gat || gats <exp> <key>\r\n
commandBuilder.append(cmd);
commandBuilder.append(' ');
commandBuilder.append(exp); // <- 필드에 직접 접근
commandBuilder.append(' ');
commandBuilder.append(keysString);
commandBuilder.append(RN_STRING);
break;| CollectionCreate setCreate = new SetCreate(flag, | ||
| attributes.getExpireTime(), attributes.getMaxCount(), | ||
| attributes.getReadable(), noreply); | ||
| CollectionCreate setCreate = new SetCreate(flag, CreateAttributes.of(attributes), false); |
There was a problem hiding this comment.
질문입니다.
기존에는 CollectionAttributes에 어떤 overflowaction이 설정되어 있더라도
set 생성 시에 반영하지 않았는 데, 현재 코드는 이를 반영하고 있습니다.
혹시 기존과의 호환성을 위해,
CollectionAttributes에 설정된 overflowaction을 null로 설정할 필요가 있을까요?
There was a problem hiding this comment.
추가 질문입니다.
내부적으로 long 타입의 exp 사용하도록 변경하는 PR인데요.
기존 API에서
int 타입으로 exp 값을 그대로 리턴하는 코드는 없는 건가요?
getattr에서 잔여시간만을 int로 리턴하는 코드는 있다고 들었습니다.
v1과 v2 interface가 같이 사용될 때,
v2에서 long 타입의 값을 넣고 v1에서 int 타입으로 exp 값을 얻는 경우는 없나요?
There was a problem hiding this comment.
CollectionAttributes에 설정된 overflowaction을 null로 설정할 필요가 있을까요?
Map, Set에서는 사용자가 지정한 값으로 서버로 넘기고 ATTR_ERROR 가 발생하는 케이스가 더 적합하다고 보여지긴 합니다.
오히려 기존 방식의 경우 overflowAction를 유효하지 않은 값으로 Create 요청한 경우, 사용자는 정상 응답으로 확인하고 getattr 명령어로 가져왔을 때 CollectionOverflowAction.error 으로 설정되었을 경우 혼란스러울 것 같다고 보여집니다.
There was a problem hiding this comment.
기존 API에서
int 타입으로 exp 값을 그대로 리턴하는 코드는 없는 건가요?
v1 에서는 CollectionFuture<CollectionAttributes> asyncGetAttr(final String key); 를 사용합니다.
즉, 기존의 CollectionAttributes (int expireTime) 을 사용하기 때문에 int 타입으로 반환을 합니다.
v1과 v2 interface가 같이 사용될 때,
v2에서 long 타입의 값을 넣고 v1에서 int 타입으로 exp 값을 얻는 경우는 없나요?
이 경우도 문제 없습니다.
There was a problem hiding this comment.
v1 에서는
CollectionFuture<CollectionAttributes> asyncGetAttr(final String key);를 사용합니다.
즉, 기존의CollectionAttributes (int expireTime)을 사용하기 때문에 int 타입으로 반환을 합니다.
exp 값을 그대로 리턴하는 경우는 없고, getattr에서 잔여시간만을 int로 리턴하는 코드만 있는 거군요.
그래서, 아주 큰 long 값을 int로 캐스팅하여 리턴하는 경우는 없는 걸로 알겠습니다.
45290c1 to
b50825a
Compare
🔗 Related Issue
⌨️ What I did
v2 API의 만료 시간 (expiration time) 파라미터 타입을
int에서long으로 변경합니다.이를 통해
int범위를 넘는 Unix timestamp 기반 만료 시각(e.g. 2038년 이후 절대 시각)을 사용할 수 있습니다.long exp를 받도록 변경long만료 시간을 담는AttributesCreate도입OperationFactory,ops/*Operation -> getExpiration method, `ASCII / Binary 프로토콜 구현체까지 타입 변경long값을 그대로 사용int범위를 넘는 값은 예외 처리기존 API(
MemcachedClient,ArcusClient)는 변경되지 않으며int만료 파라미터가long으로 자동 형 변환(auto-widening)이 되어 기존 사용자 코드에는 영향이 없습니다.