Code Monkey home page Code Monkey logo

arcus-java-client's Introduction

arcus-java-client: Arcus Java Client CI License

This is a fork of spymemcached with the following modifications to support Arcus memcached cloud.

  • Collection data types
    • List: A doubly-linked list.
    • Set: An unordered set of unique data.
    • Map: An unordered set of <field, value>.
    • B+Tree: A B+Tree structure similar to sorted map.
  • ZooKeeper based clustering

JDK Requirements

Compatible with jdk version

  • runtime requirements : At least 1.6
  • build requirements : At least 1.8

Getting Started

The Maven artifact for arcus java client is in the central Maven repository. To use it, add the following dependency to your pom.xml.

<dependencies>
	<dependency>
		<groupId>com.navercorp.arcus</groupId>
		<artifactId>arcus-java-client</artifactId>
		<version>1.13.3</version>
	</dependency>
</dependencies>

Building

To build your own library, simply run the following maven command:

$ mvn clean install

# Test cases may not run properly if you do not already have memcached
# and ZooKeeper installed on the local machine.  To skip tests, use skipTests.

$ mvn clean install -DskipTests=true

Running Test Cases

Before running test cases, make sure to set up a local ZooKeeper and run an Arcus memcached instance. Several Arcus specific test cases assume that there is an Arcus instance running, along with ZooKeeper.

First, make a simple ZooKeeper configuration file. By default, tests assume ZooKeeper is running at localhost:2181.

$ cat test-zk.conf
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial 
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between 
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
dataDir=/home1/openarcus/zookeeper_data
# the port at which the clients will connect
clientPort=2181
maxClientCnxns=200

Second, create znodes for one memcached instance running at localhost:11211. ZooKeeper comes with a command line tool. The following script uses it to set up the directory structure.

$ cat setup-test-zk.bash

ZK_CLI="./zookeeper/bin/zkCli.sh"
ZK_ADDR="-server localhost:2181"

$ZK_CLI $ZK_ADDR create /arcus 0
$ZK_CLI $ZK_ADDR create /arcus/cache_list 0
$ZK_CLI $ZK_ADDR create /arcus/cache_list/test 0
$ZK_CLI $ZK_ADDR create /arcus/client_list 0
$ZK_CLI $ZK_ADDR create /arcus/client_list/test 0
$ZK_CLI $ZK_ADDR create /arcus/cache_server_mapping 0
$ZK_CLI $ZK_ADDR create /arcus/cache_server_log 0
$ZK_CLI $ZK_ADDR create /arcus/cache_server_mapping/127.0.0.1:11211 0
$ZK_CLI $ZK_ADDR create /arcus/cache_server_mapping/127.0.0.1:11211/test 0
$ZK_CLI $ZK_ADDR create /arcus/cache_server_mapping/127.0.0.1:11212 0
$ZK_CLI $ZK_ADDR create /arcus/cache_server_mapping/127.0.0.1:11212/test 0

Now start the ZooKeeper instance using the configuration above.

$ ZOOCFGDIR=$PWD ./zookeeper/bin/zkServer.sh start test-zk.conf

And, start the memcached instance.

$ /home1/openarcus/bin/memcached -E /home1/openarcus/lib/default_engine.so -p 11211 -z localhost:2181

Finally, run test cases.

$ mvn test
[...]
Results :

Tests run: 722, Failures: 0, Errors: 0, Skipped: 8

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3:17.308s
[INFO] Finished at: Thu Mar 06 13:42:58 KST 2014
[INFO] Final Memory: 9M/722M
[INFO] ------------------------------------------------------------------------

API Documentation

Please refer to Arcus Java Client User Guide for the detailed usage of Arcus java client.

Issues

If you find a bug, please report it via the GitHub issues page.

https://github.com/naver/arcus-java-client/issues

Arcus Contributors

In addition to those who had contributed to the original libmemcached, the following people at NAVER have contributed to arcus-java-client.

Chisu Yu (netspider) [email protected]; [email protected]
Hoonmin Kim (harebox) [email protected]; [email protected]
YeaSol Kim (ngleader) [email protected]; [email protected]
SeongHwa Ahn [email protected]; [email protected]
HyongYoub Kim [email protected]

License

Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0

Patents

Arcus has patents on b+tree smget operation. Refer to PATENTS file in this directory to get the patent information.

Under the Apache License 2.0, a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable patent license is granted to any user for any usage. You can see the specifics on the grant of patent license in LICENSE file in this directory.

arcus-java-client's People

Contributors

aiceru avatar computerphilosopher avatar devhue avatar eunji6546 avatar gadimli93 avatar greenmonn avatar hjyun328 avatar hoonmin avatar hyongyoubkim avatar jhpark816 avatar jkjh0819 avatar jooho812 avatar minkikim89 avatar minwoojin avatar rudeus avatar seongminy avatar suhwanjang avatar supniverse avatar thjeong917 avatar uhm0311 avatar voyageth avatar weirdjh avatar whchoi83 avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

arcus-java-client's Issues

arcus-java-client API 재점검.

arcus-java-client API를 아래 관점에서 재검검한다.

  • enough set of APIs를 제공하는가 ?
  • 각 API의 interface는 타당한가 ?
  • 각 API에 사용된 용어는 적합한가 ?

Backward compatiliity 문제로 쉽게 변경하지 못하겠지만,
한번 정리해 두면 좋을 것 같습니다.

CI 환경 구축 및 체크인 테스트 환경 구성

지금까지 수동으로 수행하는 mvn test 에 의존하고 있었는데, 효율적인 개발 진행을 위해서 CI 환경 구축이 도움이 많이 될 것 같습니다. 도입에 들어가는 코스트나 러닝커브는 조금 있겠지만, 장기적으로 보았을 때 실보다는 득이 많으리라 판단됩니다. 저도 CI 에 대해서 이론적으로나 실무적으로나 아는 것이 거의 없는 터라 조금씩이라도 내용 찾아보고 공유하도록 하겠습니다. 코드 보다가 다른 일 하고 싶을때 한번씩 의견 달아주세요 😄

  • 아래는 네이버 이기열 책임님 건의입니다.
  • CI 환경은 염두해 두신게 없으시면 travis ci 는 어떤지 검토해 주세요. github 에 올라있는 프로젝트는 무료이고, 외부 커미터도 검증할 수 있고, 무엇보다 체크인 테스트가 여기 들어있으면 커밋 이후 별도로 시험할 필요가 없어 좋을것 같습니다. 다만, 이건 건의 수준입니다.

replication 사용 플래그 설정의 재검토.

java client에서 replication 사용하기 위해서는 해당 replication flag를 설정해야 합니다.

이러한 불편함이 replication 적용에 하나의 장벽이 되는 건지 다시 한번 논의해 봅시다.

optimize() 코드 검증

연속된 2개 이상의 연산의 get 연산이어야 optimize 할 수 있을 건데요..

  • 첫 번째 writeQ.peek()이 GetOperation이면, writeQ.remove() 하고 나서,
  • 두 번째 writeQ.peek()이 GetOperation이면, 아무 일도 하지 않고 optimize()에서 리턴합니다.

그러면, 처음에 writeQ.remove()한 operation은 처리되지 않을 것 같은 데, 버그 아닌가요 ?

    protected void optimize() {
        // make sure there are at least two get operations in a row before
        // attempting to optimize them.
        if(writeQ.peek() instanceof GetOperation) {
            optimizedOp=writeQ.remove();
            if(writeQ.peek() instanceof GetOperation) {
                OptimizedGetImpl og=new OptimizedGetImpl(
                        (GetOperation)optimizedOp);
                optimizedOp=og;

                while(writeQ.peek() instanceof GetOperation) {
                    GetOperationImpl o=(GetOperationImpl) writeQ.remove();
                    if(!o.isCancelled()) {
                        og.addOperation(o);
                    }
                }

                // Initialize the new mega get
                optimizedOp.initialize();
                assert optimizedOp.getState() == OperationState.WRITING;
                ProxyCallback pcb=(ProxyCallback) og.getCallback();
                getLogger().debug("Set up %s with %s keys and %s callbacks",
                    this, pcb.numKeys(), pcb.numCallbacks());
            }
        }
    }

pre-commit scripts 추가

commit - push 하기 전에 간단한 lint 확인을 위한 pre-commit scripts 를 추가한다.
해당 내용은 8.3 Git맞춤 - Git Hooks에 자세하게 설명되어 있다.

현재 arcus-java-client 의 .git directory 아래에는 hooks 가 없는 상태이다.
pre-commit scripts 에서는 [Java/C Client] Coding Style Guide 작성 이슈에서 논의된 내용을 바탕으로 작성된 Jam2in Java Coding Style Guide 의 내용을 점검한다.

그 외에도 lint 검사로 추가할 것이 있으면 논의를 통해 추가한다.

setArcusReplEnabled 사용에 대한 message 수정

setArcusReplEnabled 플래그를 사용하며 응용에서 정확한 message를 받지 못해 헷갈려하는 경우가 잦다.
replication 을 사용하던지 안하던지 serviceCode를 정해진 설정에서 찾지 못한다면 양쪽을 다 확인하여 replication 플래그를 잘못설정한 게 아닌지에 대한 메시지를 던지도록 변경해야한다.

Map 자료구조 직렬화, 역직렬화 버그

  • CollectionAttributes에 만료기간만 정한 후 insert에 해당 attribute를 넣어 생성과 함께 필드를 할당하면,

  • 이후 다시 가져왔을 때 가장 먼저 집어넣은 키, 값 중 값의 클래스로 고정되어 인식됩니다. 실제 케이스에선 Long이 가장 먼저 삽입되었습니다.

    • 시도항목
      • Serializable 구현 후 UID지정
    • telnet을 통한 확인 시, 키 이름과 값은 입력이 됐습니다.
    • 추후 get한 후 각 필드를 알맞은 클래스로 형변환 시도 시 Long타입을 해당 타입으로 변경할 수 없다는 에러메세지가 발생합니다.
  • 정상적인 방법으로 OTHERS 타입으로 생성 및 값 입력

    • Integer, Long의 경우 잘 들어갔으나, 클래스(Serializable)의 인스턴스를 넣으면 반영되지 않았습니다.
    • client를 통해 다시 조회하여 가져올 때, Integer, Long타입의 경우 decode에러가 발생했으며 클래스의 인스턴스는 필드가 인식되지 않았습니다.
    • 입력된 arcus에서 ascii를 통해 조회했을 때,
creationTime 6 
maxInactiveTime 2 %^&$(인코딩 실패)
lastAaccessedTime 6 %^&$(인코딩 실패)

실제 자료형은 각각
long, integer, long 순입니다.
으로 입력되었으며 caught ioexception decoding 2(위 예시의 숫자) bytes of data가 항목마다 발생했습니다.
조치방법: STRING형으로 생성 후, JSON으로 직렬화 후 가져올 때마다 다시 역직렬화하는 방식으로 대체했습니다.

modify next index issue 수정 빠진 부분 추가

modify that next index will be processed when bulk and pipe opeartion moved by switchover
commit : 0de1c2e
issue 및 commit에서 빠진 부분이 있어서 추가 합니다.
CollectionPipedUpdate btree 부분 수정이 필요합니다.

fillWriteBuffer() 코드 검증.

아래 코드에서 bytesToCopy는 아래 둘 중의 작은 값으로 설정해야 하지 않나요 ?

  • obuf.remaining()
  • getWbuf().capacity() - getWbuf().remaining()
    public final void fillWriteBuffer(boolean shouldOptimize) {
        if(toWrite == 0 && readQ.remainingCapacity() > 0) {
            getWbuf().clear();
            Operation o=getCurrentWriteOp();
            while(o != null && toWrite < getWbuf().capacity()) {
                assert o.getState() == OperationState.WRITING;
                // This isn't the most optimal way to do this, but it hints
                // at a larger design problem that may need to be taken care
                // if in the bowels of the client.
                // In practice, readQ should be small, however.
                if(!readQ.contains(o)) {
                    readQ.add(o);
                }

                ByteBuffer obuf=o.getBuffer();
                assert obuf != null : "Didn't get a write buffer from " + o;
                int bytesToCopy=Math.min(getWbuf().remaining(),
                        obuf.remaining());
                byte b[]=new byte[bytesToCopy];
                obuf.get(b);
                getWbuf().put(b);
                getLogger().debug("After copying stuff from %s: %s",
                        o, getWbuf());
                if(!o.getBuffer().hasRemaining()) {
                    o.writeComplete();
                    transitionWriteItem();

                    preparePending();
                    if(shouldOptimize) {
                        optimize();
                    }

                    o=getCurrentWriteOp();
                }
                toWrite += bytesToCopy;
            }
            getWbuf().flip();
            assert toWrite <= getWbuf().capacity()
                : "toWrite exceeded capacity: " + this;
            assert toWrite == getWbuf().remaining()
                : "Expected " + toWrite + " remaining, got "
                + getWbuf().remaining();
        } else {
            getLogger().debug("Buffer is full, skipping");
        }
    }

pipe 연산과 다수 연산을 던지는 방식 비교

다수 연산을 수행함에 있어, 아래 두 방식의 성능과 개발 편이성 비교..

  • pipe 연산을 이용하는 방식
  • 다수 연산을 async하게 요청하는 방식
    • 다수 연산을 async하게 요청
    • 다수 future 객체 관리
    • 다수 future 객체에서 전체 결과 조회

asyncGetAttr 수행 시의 오류 메세지 발생.

asyncGetAttr 수행 시, cache server는 정상 response string을 던지지만 java client는 아래와 같은 메세지를 출력합니다.

2016-08-17 11:12:27.359 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl:  Unexpected operation status : ATTR type=kv
2016-08-17 11:12:27.360 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl:  Unexpected operation status : ATTR flags=0
2016-08-17 11:12:27.360 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl:  Unexpected operation status : ATTR expiretime=0
2016-08-17 11:12:27.361 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl:  Unexpected operation status : ATTR type=kv
2016-08-17 11:12:27.362 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl:  Unexpected operation status : ATTR flags=0
2016-08-17 11:12:27.362 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl:  Unexpected operation status : ATTR expiretime=0
2016-08-17 11:12:27.365 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl:  Unexpected operation status : ATTR type=kv
2016-08-17 11:12:27.365 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl:  Unexpected operation status : ATTR flags=0
2016-08-17 11:12:27.366 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl:  Unexpected operation status : ATTR expiretime=0
2016-08-17 11:12:27.367 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl:  Unexpected operation status : ATTR type=kv
2016-08-17 11:12:27.367 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl:  Unexpected operation status : ATTR flags=0
2016-08-17 11:12:27.368 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl:  Unexpected operation status : ATTR expiretime=0
2016-08-17 11:12:27.369 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl:  Unexpected operation status : ATTR type=kv
2016-08-17 11:12:27.370 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl:  Unexpected operation status : ATTR flags=0
2016-08-17 11:12:27.370 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl:  Unexpected operation status : ATTR expiretime=0
2016-08-17 11:12:27.371 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl:  Unexpected operation status : ATTR type=kv
2016-08-17 11:12:27.372 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl:  Unexpected operation status : ATTR flags=0
2016-08-17 11:12:27.372 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl:  Unexpected operation status : ATTR expiretime=0
2016-08-17 11:12:27.374 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl:  Unexpected operation status : ATTR type=kv
2016-08-17 11:12:27.375 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl:  Unexpected operation status : ATTR flags=0
2016-08-17 11:12:27.376 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl:  Unexpected operation status : ATTR expiretime=0
2016-08-17 11:12:27.377 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl:  Unexpected operation status : ATTR type=kv
2016-08-17 11:12:27.377 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl:  Unexpected operation status : ATTR flags=0
2016-08-17 11:12:27.378 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl:  Unexpected operation status : ATTR expiretime=0
...

debug log 출력 방식 일치

java client 전체적으로 debug log 를 출력할 때 아래와 같이 두 가지 방식을 혼용하고 있다.
한 가지 방식으로 통일한다.

        getLogger().debug("Got line %s", line);
        if (getLogger().isDebugEnabled()) {
            getLogger().debug("Got line %s", line);
        }

중복된 Test code 제거 작업

테스트 함수들 중 ~~~UsingSingleClient() 코드의 목적이 불분명하고, 코드 중복이 일어나고 있어 삭제하기로 결정함.

arcus client pool 을 사용하는 경우와 단일 arcus client 를 사용하는 경우로 나누어 테스트하려고 했던 것으로 추측되나, ArcusClientPool 의 경우 모든 API 호출이 this.getClient().~~~() 호출로 이어지기 때문에 굳이 나누어 테스트하는 것이 불필요하다고 판단됨.

Test Case 중 testTimeout() 실패 케이스

travis CI 테스트 도중 아래와 같은 문제가 있어 이슈 남깁니다.

testTimeout() 테스트가
request 를 날린 다음, 바로 future.get 을 수행하는데 timeout 을 1ms 또는 1ns 로 아주 짧게 주어
타임아웃 발생을 유도하는 방식입니다.

상황에 따라 다른 것 같긴 한데 현재까지 확인한 바로는
BopInsertBulkTest.testTimeout()
FlushByPrefixTest.testTimeout()
future.get() 에서 타임아웃이 발생하지 않아 테스트 Failure 되는 사례가 있었습니다.

모든 테스트 클래스의 testTimeout() 테스트에 대해 재고가 필요할 것 같습니다.

ClientBaseCase 의 CFB class 설계 오류

ClientBaseCase 의 CFB class 에 설계상 오류가 존재합니다.

ClientBaseCase 의 CFB 의 본래 목적은
각 junit test 에서 test 성격에 맞는 설정을 갖는 ConnectionFactory 를 생성하고.
이것을 CFB에 넘겨주면 이것 이외에는 DefaultConnectionFactory 의 값을 사용하도록 하기 위함입니다.
아래 코드를 보시면 이해가 쉽습니다.

ClientBaseCase.java

    protected void initClient() throws Exception {
        initClient(new DefaultConnectionFactory() {
            @Override
            public long getOperationTimeout() {
                return 15000;
            }

            @Override
            public FailureMode getFailureMode() {
                return FailureMode.Retry;
            }
        });
    }

    protected void initClient(ConnectionFactory cf) throws Exception {
        if (USE_ZK) {
            openFromZK(new CFB(cf));
        } else {
            openDirect(new CFB(cf));
        }
    }

ClientBaseCase.CFB

    private static class CFB extends ConnectionFactoryBuilder {

        private final ConnectionFactory inner;

        public CFB(ConnectionFactory cf) {
            this.inner = cf;
        }

        @Override
        public ConnectionFactory build() {
            return new ConnectionFactory() {
                @Override
                public MemcachedConnection createConnection(
                        List<InetSocketAddress> addrs) throws IOException {
                    return inner.createConnection(addrs);
                }
...
                @Override
                public Collection<ConnectionObserver> getInitialObservers() {
                    return inner.getInitialObservers();
                }
...
            };
        }

        @Override
        public ConnectionFactoryBuilder setInitialObservers(
                Collection<ConnectionObserver> obs) {
            return this;
        }
    }

하지만 설계(?)의 문제로 인하여 본래의 의도대로 코드가 동작하지 않습니다.
정확히는 대부분의 코드는 문제가 되지 않지만, 특정 부분에서 문제가 발생합니다.

그 중에 하나가 CFB 의 inner.createConnection(addrs) 입니다.
여기서의 inner 는 ClientBaseCase.initClient() 에서 생성된 DefaultConnectionFactory 인데, createConnection 코드를 보면 아래와 같습니다.
DefaultConnectionFactory.java

    public MemcachedConnection createConnection(List<InetSocketAddress> addrs)
        throws IOException {
        return new MemcachedConnection(getReadBufSize(), this, addrs,
            getInitialObservers(), getFailureMode(), getOperationFactory());
    }

여기서 getInitialObservers() 는 코드상 무조건 아래 코드입니다.
DefaultConnectionFactory.getinitialObservers

    public Collection<ConnectionObserver> getInitialObservers() {
        return Collections.emptyList();
    }

이렇게 되면 USE_ZK=true 로 테스트 코드를 실행할 경우,
CacheManager.createArcusClient() 에서 latch 때문에 10초를 대기하게 됩니다.
이러한 문제는 DefaultConnectionFactory 에는 멤버 변수이 기본 값을 return 하면서,
ConnectionFactoryBuilder 의 멤버 변수에 set 을 한 뒤 get 을 하는 설정 들은 모두 문제가 됩니다.
그 예가 initial observers 입니다.

설명이 좀 어렵지만 코드를 찬찬히 읽어보시면 이해가 될 것 같습니다.
현재 발견한 문제는 observers 만 발생하지만 다른 connection config 에도 문제가 될 수 있습니다.
ClientBaseCase 의 CFB 만 수정하거나 ClientBaseCase.initClient(ConnectionFactory cf) 만 수정해서는 해결할 문제가 아니고,
ClientBaseCase 를 상속받아 initClient(ConnectionFactory cf) 를 사용하는 모든 테스트를 수정해야 합니다.

mvn test 시 USE_ZK 옵션에 대한 논의

USE_ZK 옵션 필요 여부에 대한 논의가 필요합니다.
현재는 USE_ZK=false 일 경우에도, ZK_HOST / ZK_SERVICE_CODE 를 환경에 맞게 설정해 주어야 mvn test 가 성공합니다.

참조 : maven test 관련 이슈

ARCUS 솔루션 자체가 ZK 를 내부적으로 포함하고 있는 구조이니, USE_ZK 를 없애고 default true 로 가져갈지, 아니면 ZK 없이 arcus-memcached 를 단독으로 사용하는 경우까지를 배려할지에 대해 논의가 필요합니다.

Operation Timeout 로그에 TimeUnit 추가

operation timeout 발생 시 아래와 같이 로그가 출력되고 있습니다.

net.spy.memcached.internal.CheckedOperationTimeoutException: Timed out waiting for operation. >3 - failing node: /10.144.146.17:11211 [READING] [#
Tops=406766 #iq=1 #Wops=0 #Rops=1 #CT=1 #TR=-1]

위에서 3이라는 timeout 값이 어떤 단위를 사용하고 있는지 전혀 알 수 없는 상태입니다.
로그에서 TimeUnit 값을 함께 출력하는 것이 분석에 도움이 될 것 같습니다.

matchStatus 내에서 불필요한 log 출력 제거

OperationImpl.matchStatus 내에 아래와 같은 코드가 있다.

        if(rv == null) {
            rv=new OperationStatus(false, line);
            /* ENABLE_REPLICATION if */
            getLogger().error("Unexpected operation status : %s", line);
            /* ENABLE_REPLICATION end */
        }

위 코드는 replication 개발 당시 debug 를 위해 추가했던 내용이다.
실제 배포 시에 제거되었어야 하는 코드인데, 그대로 배포되었다.

삭제하도록 한다.

Boxing 타입 생성자 대신 valueOf 메서드 사용

설명

Boxing 타입은 Java 9 이후로 new 생성자를 이용하는 것이 deprecated 되었습니다.
최신 버전의 Java와의 호환성을 위해 valueOf 메서드를 활용하는 편이 것이 좋을 것 같습니다.

에러로그

[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/SerializingTranscoder.java:[86,16] Integer(int) in java.lang.Integer has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/SerializingTranscoder.java:[89,16] Long(long) in java.lang.Long has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/SerializingTranscoder.java:[95,16] Byte(byte) in java.lang.Byte has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/SerializingTranscoder.java:[98,16] Float(float) in java.lang.Float has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/SerializingTranscoder.java:[101,16] Double(double) in java.lang.Double has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/ArcusClient.java:[1751,22] Integer(java.lang.String) in java.lang.Integer has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/ArcusClient.java:[4437,24] Long(java.lang.String) in java.lang.Long has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/CollectionTranscoder.java:[89,16] Integer(int) in java.lang.Integer has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/CollectionTranscoder.java:[92,16] Long(long) in java.lang.Long has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/CollectionTranscoder.java:[98,16] Byte(byte) in java.lang.Byte has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/CollectionTranscoder.java:[101,16] Float(float) in java.lang.Float has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/CollectionTranscoder.java:[104,16] Double(double) in java.lang.Double has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/WhalinTranscoder.java:[66,16] Integer(int) in java.lang.Integer has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/WhalinTranscoder.java:[69,16] Short(short) in java.lang.Short has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/WhalinTranscoder.java:[72,16] Long(long) in java.lang.Long has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/WhalinTranscoder.java:[78,16] Byte(byte) in java.lang.Byte has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/WhalinTranscoder.java:[81,16] Float(float) in java.lang.Float has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/WhalinTranscoder.java:[84,16] Double(double) in java.lang.Double has been deprecated and marked for removal

Java 17 버전 기준으로 컴파일하는 경우 위와 같은 WARNING이 발생

변경사항

아래 코드는 net.spy.memcached.transcoders.SerializingTranscoder의 decode 메서드입니다.

AS-IS

public Object decode(CachedData d) {
  // ...
  case SPECIAL_INT:
    rv = new Integer(tu.decodeInt(data));
    break;
  case SPECIAL_LONG:
    rv = new Long(tu.decodeLong(data));
    break;
  // ...
}

TO-BE

public Object decode(CachedData d) {
  // ...
  case SPECIAL_INT:
    rv = Integer.valueOf(tu.decodeInt(data));
    break;
  case SPECIAL_LONG:
    rv = Long.valueOf(tu.decodeLong(data));
    break;
  // ...
}

추가사항

Spring Data Arcus의 자바 버전을 17로 설정하기 위해서는 ARCUS Java Client 또한 17 버전의 컴파일을 지원해야 합니다.
해당 문제 이외에 자바 17버전 컴파일러에서 발생하는 WARNING이 없는 것으로 보아, 해당 이슈만 해결된다면 호환성 문제는 없을 것 같습니다.

Migration 기능 추가

Server 의 Migration 동작에 맞춰 client 에 기능을 추가한다.
(본 이슈는 Server 의 개발 진척에 따라 점진적으로 이슈의 내용을 아래에 추가/완성해 나가는 것으로 한다.)

  • hash ring 에서 각 hash point 에 state 를 추가하고, state 의 상태에 따라 node 를 return 할 수 있도록 locator 에 기능을 추가한다.

updateConnection()에서의 cancel 처리 질문

replication 기능이 없는 경우의 updateConnection() 코드입니다.

Remove할 node에 있던 operations들에 대해 모두 cancel 처리를 해 줘야 할 것 같은데,
reading state에 있는 operations에 대해서는 cancel 처리 하지 않고 있습니다..

응용에서 operation timeout으로 cancel하는 것이 대부분이겠지만,
응용에서 무한히 대기하는 경우도 있을 수 있으므로,
이 부분에서 cancel 처리하는 것이 맞지 않나요 ??

        for (MemcachedNode node : locator.getAll()) {
            if (addrs.contains((InetSocketAddress) node.getSocketAddress())) {
                addrs.remove((InetSocketAddress) node.getSocketAddress());
            } else {
                removeNodes.add(node);
            }
        }

        // Make connections to the newly added nodes.
        for (SocketAddress sa : addrs) {
            attachNodes.add(attachMemcachedNode(sa));
        }

        // Update the hash.
        locator.update(attachNodes, removeNodes);

        // Remove unavailable nodes in the reconnect queue.
        for (MemcachedNode node : removeNodes) {
            getLogger().info("old memcached node removed %s", node);
            for (Entry<Long, MemcachedNode> each : reconnectQueue.entrySet()) {
                if (node.equals(each.getValue())) {
                    reconnectQueue.remove(each.getKey());
                    break;
                }
            }
            String cause = "node removed.";
            if (failureMode == FailureMode.Cancel) {
                cancelOperations(node.destroyWriteQueue(false), cause);
                cancelOperations(node.destroyInputQueue(), cause);
            } else if (failureMode == FailureMode.Redistribute || failureMode == FailureMode.Retry) {
                redistributeOperations(node.destroyWriteQueue(true), cause);
                redistributeOperations(node.destroyInputQueue(), cause);
            }
        }

Element Flag Filter 사용 시 command line 길이 및 처리방식 확인.

arcus-java-client, arcus-c-client에서
Element Flag Filter 사용 시 command line 을 어떻게 보내는지 확인하고,
최대 eflag를 주었을 때 어떻게 처리되는지 확인이 필요하다.

현재 ElementMultiFlagsFilter로 최대 100개 compare value를 지정할 수 있다.
100개의 compare value를 지정 했을 때 command line을 확인해 서버에서 처리 가능한 형태로
command를 만들어서 보내주는지에 대한 확인 작업이다.

setupResend() 이상한 부분 검증

아래는 setupResend() 코드입니다..

    public final void setupResend(boolean cancelWrite, String cause) {
        // First, reset the current write op, or cancel it if we should
        // be authenticating
        Operation op=getCurrentWriteOp();
        if((cancelWrite || shouldAuth) && op != null) {
            op.cancel(cause);
        } else if(op != null) {
            ByteBuffer buf=op.getBuffer();
            if(buf != null) {
                buf.reset();
            } else {
                getLogger().info("No buffer for current write op, removing");
                removeCurrentWriteOp();
            }
        }
        // Now cancel all the pending read operations.  Might be better to
        // to requeue them.
        while(hasReadOp()) {
            op=removeCurrentReadOp();
            if (op != getCurrentWriteOp()) {
                getLogger().warn("Discarding partially completed op: %s", op);
                op.cancel(cause);
            }
        }

        while((cancelWrite || shouldAuth) && hasWriteOp()) {
            op=removeCurrentWriteOp();
            getLogger().warn("Discarding partially completed op: %s", op);
            op.cancel(cause);
        }


        getWbuf().clear();
        getRbuf().clear();
        toWrite=0;
    }

cancelWrite = true인 경우,

  • 첫 번째 if 문에서 current write op를 cancel 처리
  • 두 번째 while 문에서 다시 current write op를 cancel 처리하고 그 op를 제거

이상한 부분은current write op에 대해 2회 cancel 처리이며,
1회 cancel 처리로 변경되어야 할 것 같습니다.

추가로, cancel 처리하는 op에 대해 buffer != null이더라도 reset 처리는 필요 없는 거죠 ?

cancelWrite = false인 경우,

  • current write op의 buffer가 null이 아니면, reset 처리
  • current write op의 buffer가 null이면, 그 op를 제거

이상한 부분은 위의 2번째 처리 로직이며,
그 op를 제거하지 않아야 할 것 같습니다.
오히려, 그 op의 initialize() 메소드를 호출해야 하지 않는 지요 ?

ketama hash collision 시의 owner 결정

[Clients] ketama hash collision 시의 owner 결정 이슈 사항입니다.
이슈 내용입니다.

여러 노드의 160 hash point 중에 서로 collistion 발생 시,

  • node의 name string 대소 비교하여,
  • 더 작은 name string을 가진 노드가 그 hash point에 대한 ownership을 가지게 처리

현재 cache server 쪽은 처리 완료한 상태이며, 최소한 Java/C clients에서 처리가 필요합니다.
참고로, python, ruby 등의 arcus client에서도 한번 확인해 주면 좋겠습니다.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.