You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bookkeeper.apache.org by si...@apache.org on 2018/06/04 22:03:54 UTC

[bookkeeper] branch branch-4.7 updated (3c5d096 -> 96d599e)

This is an automated email from the ASF dual-hosted git repository.

sijie pushed a change to branch branch-4.7
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git.


    from 3c5d096  Fix checkstyle warnings
     new 1ae9772  Provide the flag to allow ignoring startup failures on loading extra server components
     new 3cf0be8  Update bookkeeper dependencies : netty/protobuf/grpc
     new ee7f137  [TABLE] mark TableClientTest & TableClientSimpleTest as FlakyTest
     new 308cf1e  Include stream modules in bookkeeper distributions only when `-Dstream` is specified
     new 8e4c13b  [TABLE SERVICE] use grpc reverse proxy to serve storage container requests
     new 76b6857  [TABLE SERVICE] remove StorageContainerRequest and StorageContainerResponse
     new d8f7cc0  [TABLE SERVICE] cleanup : cleanup protobuf definitions
     new 87f9655  [TABLE SERVICE] cleanup : provide unified service uri for resolving service endpoints
     new 96d599e  ISSUE #1472: [TABLE SERVICE] TestStorageClientBuilder.testBuildClientInvalidNamespaceName failed

The 9 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../apache/bookkeeper/common/net/ServiceURI.java   | 235 ++++++++++++++
 .../common/{util => net}/package-info.java         |   4 +-
 .../bookkeeper/common/net/ServiceURITest.java      | 221 +++++++++++++
 .../common/testing}/annotations/FlakyTest.java     |   2 +-
 bookkeeper-dist/all/pom.xml                        |  25 +-
 bookkeeper-dist/server/pom.xml                     |  25 +-
 bookkeeper-dist/src/assemble/bin-all.xml           |  13 +-
 bookkeeper-dist/src/assemble/bin-server.xml        |  13 +-
 .../src/main/resources/LICENSE-all.bin.txt         |  93 +++---
 .../src/main/resources/LICENSE-server.bin.txt      |  92 +++---
 .../src/main/resources/NOTICE-all.bin.txt          |   2 +-
 .../src/main/resources/NOTICE-server.bin.txt       |   2 +-
 .../LICENSE                                        |   0
 .../LICENSE.base64.txt                             |   0
 .../LICENSE.jbzip2.txt                             |   0
 .../LICENSE.jfastlz.txt                            |   0
 .../LICENSE.jsr166y.txt                            |   0
 .../LICENSE.libdivsufsort.txt                      |   0
 .../LICENSE.protobuf.txt                           |   0
 .../LICENSE.slf4j.txt                              |   0
 .../LICENSE.webbit.txt                             |   0
 .../src/main/resources/deps/protobuf-3.3.1/LICENSE |  32 --
 .../{protobuf-3.4.0 => protobuf-3.5.1}/LICENSE     |   0
 .../bookkeeper/conf/ServerConfiguration.java       |  29 +-
 .../java/org/apache/bookkeeper/server/Main.java    |   8 +-
 ...KeeperDiskSpaceWeightedLedgerPlacementTest.java |   2 +-
 .../bookkeeper/client/BookieDecommissionTest.java  |   2 +-
 .../bookkeeper/proto/BookieProtoEncodingTest.java  |  19 +-
 .../org/apache/bookkeeper/server/TestMain.java     |  49 +++
 conf/bk_server.conf                                |   5 +
 pom.xml                                            |  16 +-
 site/_data/config/bk_server.yaml                   |   3 +
 .../bookkeeper/stream/cli/StreamStorageCli.java    |  13 +-
 .../clients/TestStorageClientBuilder.java          |   6 +-
 .../clients/config/StorageClientSettings.java      |  40 +--
 .../clients/impl/channel/StorageServerChannel.java |   5 +-
 .../StorageContainerClientInterceptor.java         |   4 +-
 .../clients/impl/internal/LocationClientImpl.java  |  25 +-
 .../clients/impl/internal/MetaRangeClientImpl.java |   6 +-
 .../clients/impl/internal/RootRangeClientImpl.java |   4 +-
 .../internal/mr/MetaRangeRequestProcessor.java     |  46 +--
 .../resolver/SimpleStreamResolverFactory.java      |  90 ------
 .../bookkeeper/clients/utils/GrpcChannels.java     |  64 ++++
 .../apache/bookkeeper/clients/utils/GrpcUtils.java |  18 +-
 .../clients/config/TestStorageClientSettings.java  |  15 +-
 .../clients/grpc/GrpcClientTestBase.java           |   6 +-
 .../container/TestStorageContainerChannel.java     |  13 +-
 .../impl/internal/RootRangeClientImplTestBase.java |   7 +-
 .../impl/internal/TestLocationClientImpl.java      |   4 +-
 .../impl/internal/TestMetaRangeClientImpl.java     |  25 +-
 .../TestRootRangeClientCreateNamespaceRpc.java     |   2 +-
 .../TestRootRangeClientGetNamespaceRpc.java        |   2 +-
 .../clients/impl/kv/DeleteRequestProcessor.java    |  94 ++++++
 .../clients/impl/kv/IncrementRequestProcessor.java |  94 ++++++
 .../apache/bookkeeper/clients/impl/kv/KvUtils.java |  47 ---
 .../clients/impl/kv/PByteBufTableRangeImpl.java    |  52 ++-
 .../clients/impl/kv/PutRequestProcessor.java       |  94 ++++++
 .../clients/impl/kv/RangeRequestProcessor.java     |  94 ++++++
 .../clients/impl/kv/TableRequestProcessor.java     |  93 ------
 .../clients/impl/kv/TxnRequestProcessor.java       |  94 ++++++
 .../impl/kv/DeleteRequestProcessorTest.java        | 115 +++++++
 .../impl/kv/IncrementRequestProcessorTest.java     | 115 +++++++
 .../clients/impl/kv/PutRequestProcessorTest.java   | 115 +++++++
 .../clients/impl/kv/RangeRequestProcessorTest.java | 115 +++++++
 .../clients/impl/kv/TableRequestProcessorTest.java | 217 -------------
 .../bookkeeper/clients/impl/kv/TestKvUtils.java    |  65 ----
 .../clients/impl/kv/TxnRequestProcessorTest.java   | 115 +++++++
 .../resolver/AbstractNameResolverFactory.java      |  38 ---
 .../resolver/ServiceNameResolverProvider.java      | 164 ++++++++++
 ...leNameResolver.java => StaticNameResolver.java} |   4 +-
 .../bookkeeper/common/util/ListenableFutures.java  |  10 +
 .../common/grpc/proxy/PingPongServiceTestBase.java |   4 +-
 .../common/reslover/TestSimpleNameResolver.java    |   6 +-
 .../annotations/DistributedLogAnnotations.java     |   6 -
 stream/distributedlog/core/pom.xml                 |   7 +
 .../org/apache/distributedlog/util/DLUtils.java    |  17 +-
 .../distributedlog/TestAsyncReaderWriter.java      |   3 -
 .../distributedlog/TestNonBlockingReads.java       |   2 -
 .../apache/distributedlog/TestRollLogSegments.java |   6 -
 .../apache/distributedlog/TestZooKeeperClient.java |   3 -
 .../admin/TestDistributedLogAdmin.java             |  12 +-
 .../distributedlog/bk/TestLedgerAllocator.java     |  17 +-
 .../TestDynamicConfigurationFeatureProvider.java   |  12 +-
 .../namespace/TestNamespaceBuilder.java            |   3 -
 .../stream/protocol/ProtocolConstants.java         |   3 +
 .../stream/protocol/util/ProtoUtils.java           |  91 +++---
 stream/proto/src/main/proto/kv_rpc.proto           |  20 +-
 stream/proto/src/main/proto/storage.proto          |  64 +---
 stream/proto/src/main/proto/stream.proto           |  16 +-
 .../stream/protocol/util/TestProtoUtils.java       |  24 +-
 .../bookkeeper/stream/cluster/StreamCluster.java   |  12 +-
 .../bookkeeper/stream/server/StorageServer.java    |   6 +-
 .../bookkeeper/stream/server/grpc/GrpcServer.java  |  28 +-
 .../stream/server/grpc/GrpcServerSpec.java         |   4 +-
 .../server/grpc/GrpcStorageContainerService.java   |  10 +-
 .../stream/server/service/StorageService.java      |  16 +-
 .../stream/server/grpc/TestGrpcServer.java         |   6 +-
 ...{RangeStore.java => StorageContainerStore.java} |  15 +-
 .../stream/storage/api/kv/TableStore.java          |  22 +-
 .../storage/api/metadata/MetaRangeStore.java       |   6 +-
 .../storage/api/metadata/RangeStoreService.java    |   6 +
 .../stream/storage/api/sc/StorageContainer.java    |  12 +-
 ...Container.java => StorageContainerService.java} |  36 +--
 .../api/sc/StorageContainerServiceFactory.java}    |  18 +-
 .../api/service/RangeStoreServiceFactory.java}     |  29 +-
 .../stream/storage/api/service}/package-info.java  |   4 +-
 stream/storage/impl/pom.xml                        |   5 +
 ...lder.java => StorageContainerStoreBuilder.java} |  56 ++--
 .../stream/storage/impl/RangeStoreImpl.java        | 206 ------------
 .../storage/impl/StorageContainerStoreImpl.java    | 113 +++++++
 .../storage/impl/grpc/GrpcMetaRangeService.java    |  23 +-
 .../stream/storage/impl/grpc/GrpcServices.java}    |  34 +-
 .../stream/storage/impl/grpc/GrpcTableService.java |  96 +++++-
 .../handler/StorageContainerResponseHandler.java   |  44 ---
 .../stream/storage/impl/kv/TableStoreImpl.java     | 105 +++---
 .../stream/storage/impl/kv/TableStoreUtils.java    |   5 +
 .../storage/impl/metadata/MetaRangeStoreImpl.java  |  35 +-
 .../storage/impl/metadata/RootRangeStoreImpl.java  |  27 +-
 .../stream/storage/impl/sc/Channel404.java         |  80 +++++
 .../impl/sc/DefaultStorageContainerFactory.java    |  31 +-
 .../storage/impl/sc/StorageContainer404.java}      |  39 ++-
 .../storage/impl/sc/StorageContainerImpl.java      | 336 ++++---------------
 .../impl/sc/StorageContainerRegistryImpl.java      |   8 +-
 .../FailRequestRangeStoreService.java}             |  94 +++---
 .../RangeStoreContainerServiceFactoryImpl.java     |  46 +++
 .../service/RangeStoreContainerServiceImpl.java    |  55 ++++
 .../impl/service/RangeStoreServiceFactoryImpl.java |  71 ++++
 .../RangeStoreServiceImpl.java}                    | 117 +++----
 .../stream/storage/impl}/service/package-info.java |   4 +-
 ....java => TestStorageContainerStoreBuilder.java} |  22 +-
 ...mpl.java => TestStorageContainerStoreImpl.java} | 357 +++++++++++----------
 .../impl/grpc/TestGrpcMetaRangeService.java        |  42 +--
 .../impl/grpc/TestGrpcRootRangeService.java        |  61 ++--
 .../storage/impl/grpc/TestGrpcTableService.java    | 164 +++++-----
 .../TestStorageContainerResponseHandler.java       | 115 -------
 .../stream/storage/impl/kv/TableStoreImplTest.java | 267 +++++++--------
 .../impl/metadata/MetaRangeStoreImplTest.java      |  28 +-
 .../impl/metadata/TestRootRangeStoreImpl.java      |  27 +-
 .../sc/TestDefaultStorageContainerFactory.java     |  35 +-
 .../impl/sc/TestStorageContainerRegistryImpl.java  |  23 +-
 .../impl/sc/ZkStorageContainerManagerTest.java     |  15 +-
 .../RangeStoreServiceImplTest.java}                | 167 +++++-----
 tests/integration/cluster/pom.xml                  |   8 +
 .../integration/stream/StorageAdminClientTest.java |   7 +-
 .../integration/stream/StreamClusterTestBase.java  |   7 +-
 .../integration/stream/TableClientSimpleTest.java  |   4 +-
 .../tests/integration/stream/TableClientTest.java  |   4 +-
 tests/integration/pom.xml                          |  15 +-
 148 files changed, 3726 insertions(+), 2840 deletions(-)
 create mode 100644 bookkeeper-common/src/main/java/org/apache/bookkeeper/common/net/ServiceURI.java
 copy bookkeeper-common/src/main/java/org/apache/bookkeeper/common/{util => net}/package-info.java (89%)
 create mode 100644 bookkeeper-common/src/test/java/org/apache/bookkeeper/common/net/ServiceURITest.java
 rename {bookkeeper-server/src/test/java/org/apache/bookkeeper/test => bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing}/annotations/FlakyTest.java (95%)
 rename bookkeeper-dist/src/main/resources/deps/{google-auth-library-credentials-0.4.0 => google-auth-library-credentials-0.9.0}/LICENSE (100%)
 rename bookkeeper-dist/src/main/resources/deps/{netty-4.1.12.Final => netty-4.1.22.Final}/LICENSE.base64.txt (100%)
 rename bookkeeper-dist/src/main/resources/deps/{netty-4.1.12.Final => netty-4.1.22.Final}/LICENSE.jbzip2.txt (100%)
 rename bookkeeper-dist/src/main/resources/deps/{netty-4.1.12.Final => netty-4.1.22.Final}/LICENSE.jfastlz.txt (100%)
 rename bookkeeper-dist/src/main/resources/deps/{netty-4.1.12.Final => netty-4.1.22.Final}/LICENSE.jsr166y.txt (100%)
 rename bookkeeper-dist/src/main/resources/deps/{netty-4.1.12.Final => netty-4.1.22.Final}/LICENSE.libdivsufsort.txt (100%)
 rename bookkeeper-dist/src/main/resources/deps/{netty-4.1.12.Final => netty-4.1.22.Final}/LICENSE.protobuf.txt (100%)
 rename bookkeeper-dist/src/main/resources/deps/{netty-4.1.12.Final => netty-4.1.22.Final}/LICENSE.slf4j.txt (100%)
 rename bookkeeper-dist/src/main/resources/deps/{netty-4.1.12.Final => netty-4.1.22.Final}/LICENSE.webbit.txt (100%)
 delete mode 100644 bookkeeper-dist/src/main/resources/deps/protobuf-3.3.1/LICENSE
 rename bookkeeper-dist/src/main/resources/deps/{protobuf-3.4.0 => protobuf-3.5.1}/LICENSE (100%)
 delete mode 100644 stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/resolver/SimpleStreamResolverFactory.java
 create mode 100644 stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/utils/GrpcChannels.java
 create mode 100644 stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/DeleteRequestProcessor.java
 create mode 100644 stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/IncrementRequestProcessor.java
 create mode 100644 stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/PutRequestProcessor.java
 create mode 100644 stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/RangeRequestProcessor.java
 delete mode 100644 stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/TableRequestProcessor.java
 create mode 100644 stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/TxnRequestProcessor.java
 create mode 100644 stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/DeleteRequestProcessorTest.java
 create mode 100644 stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/IncrementRequestProcessorTest.java
 create mode 100644 stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/PutRequestProcessorTest.java
 create mode 100644 stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/RangeRequestProcessorTest.java
 delete mode 100644 stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/TableRequestProcessorTest.java
 create mode 100644 stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/TxnRequestProcessorTest.java
 delete mode 100644 stream/common/src/main/java/org/apache/bookkeeper/common/resolver/AbstractNameResolverFactory.java
 create mode 100644 stream/common/src/main/java/org/apache/bookkeeper/common/resolver/ServiceNameResolverProvider.java
 rename stream/common/src/main/java/org/apache/bookkeeper/common/resolver/{SimpleNameResolver.java => StaticNameResolver.java} (94%)
 rename stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/{RangeStore.java => StorageContainerStore.java} (68%)
 copy stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/sc/{StorageContainer.java => StorageContainerService.java} (57%)
 copy stream/{cli/src/main/java/org/apache/bookkeeper/stream/cli/commands/SubCommand.java => storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/sc/StorageContainerServiceFactory.java} (66%)
 copy stream/{api/src/main/java/org/apache/bookkeeper/api/kv/result/Result.java => storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/service/RangeStoreServiceFactory.java} (63%)
 copy {bookkeeper-common/src/main/java/org/apache/bookkeeper/common/util => stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/service}/package-info.java (88%)
 rename stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/{RangeStoreBuilder.java => StorageContainerStoreBuilder.java} (72%)
 delete mode 100644 stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/RangeStoreImpl.java
 create mode 100644 stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/StorageContainerStoreImpl.java
 copy stream/{distributedlog/core/src/main/java/org/apache/distributedlog/logsegment/LogSegmentFilter.java => storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/grpc/GrpcServices.java} (51%)
 delete mode 100644 stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/grpc/handler/StorageContainerResponseHandler.java
 create mode 100644 stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/Channel404.java
 copy stream/{distributedlog/core/src/main/java/org/apache/distributedlog/lock/NopDistributedLock.java => storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/StorageContainer404.java} (59%)
 rename stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/{sc/FailRequestStorageContainer.java => service/FailRequestRangeStoreService.java} (55%)
 create mode 100644 stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreContainerServiceFactoryImpl.java
 create mode 100644 stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreContainerServiceImpl.java
 create mode 100644 stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreServiceFactoryImpl.java
 copy stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/{sc/StorageContainerImpl.java => service/RangeStoreServiceImpl.java} (69%)
 copy {bookkeeper-server/src/main/java/org/apache/bookkeeper/server => stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl}/service/package-info.java (87%)
 rename stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/{TestRangeStoreBuilder.java => TestStorageContainerStoreBuilder.java} (84%)
 rename stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/{TestRangeStoreImpl.java => TestStorageContainerStoreImpl.java} (58%)
 delete mode 100644 stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/handler/TestStorageContainerResponseHandler.java
 rename stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/{sc/StorageContainerImplTest.java => service/RangeStoreServiceImplTest.java} (74%)

-- 
To stop receiving notification emails like this one, please contact
sijie@apache.org.

[bookkeeper] 06/09: [TABLE SERVICE] remove StorageContainerRequest and StorageContainerResponse

Posted by si...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sijie pushed a commit to branch branch-4.7
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git

commit 76b6857725bf25e77e4db285a27692c13c022ebb
Author: Sijie Guo <si...@apache.org>
AuthorDate: Wed May 30 10:18:15 2018 -0700

    [TABLE SERVICE] remove StorageContainerRequest and StorageContainerResponse
    
    Descriptions of the changes in this PR:
    
    *Motivation*
    
     #1448 uses reverse proxy for serving storage container requests and responses. so the `StorageContainerRequest` and `StorageContainerResponse`
     become redundant.
    
    *Solution*
    
    removes `StorageContainerRequest` and `StorageContainerResponse`
    
    Master Issue: #1205
    
    Author: Sijie Guo <si...@apache.org>
    
    Reviewers: Enrico Olivelli <eo...@gmail.com>, Jia Zhai <None>
    
    This closes #1452 from sijie/remove_storage_container_request_response
---
 .../clients/impl/channel/StorageServerChannel.java |   4 +-
 .../clients/impl/internal/MetaRangeClientImpl.java |   6 +-
 .../internal/mr/MetaRangeRequestProcessor.java     |  46 ++--
 .../impl/internal/TestMetaRangeClientImpl.java     |  20 +-
 .../clients/impl/kv/DeleteRequestProcessor.java    |  94 ++++++++
 .../clients/impl/kv/IncrementRequestProcessor.java |  94 ++++++++
 .../apache/bookkeeper/clients/impl/kv/KvUtils.java |  47 ----
 .../clients/impl/kv/PByteBufTableRangeImpl.java    |  52 ++--
 .../clients/impl/kv/PutRequestProcessor.java       |  94 ++++++++
 .../clients/impl/kv/RangeRequestProcessor.java     |  94 ++++++++
 .../clients/impl/kv/TableRequestProcessor.java     |  93 -------
 .../clients/impl/kv/TxnRequestProcessor.java       |  94 ++++++++
 .../impl/kv/DeleteRequestProcessorTest.java        | 115 +++++++++
 .../impl/kv/IncrementRequestProcessorTest.java     | 115 +++++++++
 .../clients/impl/kv/PutRequestProcessorTest.java   | 115 +++++++++
 .../clients/impl/kv/RangeRequestProcessorTest.java | 115 +++++++++
 .../clients/impl/kv/TableRequestProcessorTest.java | 217 -----------------
 .../bookkeeper/clients/impl/kv/TestKvUtils.java    |  65 -----
 .../clients/impl/kv/TxnRequestProcessorTest.java   | 115 +++++++++
 .../stream/protocol/util/ProtoUtils.java           |  25 +-
 stream/proto/src/main/proto/kv_rpc.proto           |  20 +-
 stream/proto/src/main/proto/storage.proto          |  50 +---
 .../stream/storage/api/kv/TableStore.java          |  22 +-
 .../storage/api/metadata/MetaRangeStore.java       |   6 +-
 .../storage/impl/grpc/GrpcMetaRangeService.java    |  21 +-
 .../stream/storage/impl/grpc/GrpcTableService.java |  96 ++++++--
 .../handler/StorageContainerResponseHandler.java   |  44 ----
 .../stream/storage/impl/kv/TableStoreImpl.java     | 105 ++++----
 .../stream/storage/impl/kv/TableStoreUtils.java    |   5 +
 .../storage/impl/metadata/MetaRangeStoreImpl.java  |  35 +--
 .../impl/service/FailRequestRangeStoreService.java |  59 +++--
 .../impl/service/RangeStoreServiceImpl.java        |  57 ++---
 .../impl/TestStorageContainerStoreImpl.java        | 135 +++++------
 .../impl/grpc/TestGrpcMetaRangeService.java        |  34 +--
 .../storage/impl/grpc/TestGrpcTableService.java    | 144 ++++++-----
 .../TestStorageContainerResponseHandler.java       | 115 ---------
 .../stream/storage/impl/kv/TableStoreImplTest.java | 267 +++++++++------------
 .../impl/metadata/MetaRangeStoreImplTest.java      |  28 +--
 .../impl/service/RangeStoreServiceImplTest.java    | 155 ++++++------
 39 files changed, 1690 insertions(+), 1328 deletions(-)

diff --git a/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/channel/StorageServerChannel.java b/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/channel/StorageServerChannel.java
index d9e9388..8660aab 100644
--- a/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/channel/StorageServerChannel.java
+++ b/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/channel/StorageServerChannel.java
@@ -31,14 +31,14 @@ import org.apache.bookkeeper.clients.impl.container.StorageContainerClientInterc
 import org.apache.bookkeeper.clients.resolver.EndpointResolver;
 import org.apache.bookkeeper.clients.utils.GrpcUtils;
 import org.apache.bookkeeper.stream.proto.common.Endpoint;
+import org.apache.bookkeeper.stream.proto.kv.rpc.TableServiceGrpc;
+import org.apache.bookkeeper.stream.proto.kv.rpc.TableServiceGrpc.TableServiceFutureStub;
 import org.apache.bookkeeper.stream.proto.storage.MetaRangeServiceGrpc;
 import org.apache.bookkeeper.stream.proto.storage.MetaRangeServiceGrpc.MetaRangeServiceFutureStub;
 import org.apache.bookkeeper.stream.proto.storage.RootRangeServiceGrpc;
 import org.apache.bookkeeper.stream.proto.storage.RootRangeServiceGrpc.RootRangeServiceFutureStub;
 import org.apache.bookkeeper.stream.proto.storage.StorageContainerServiceGrpc;
 import org.apache.bookkeeper.stream.proto.storage.StorageContainerServiceGrpc.StorageContainerServiceFutureStub;
-import org.apache.bookkeeper.stream.proto.storage.TableServiceGrpc;
-import org.apache.bookkeeper.stream.proto.storage.TableServiceGrpc.TableServiceFutureStub;
 
 /**
  * A channel connected to a range server.
diff --git a/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/internal/MetaRangeClientImpl.java b/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/internal/MetaRangeClientImpl.java
index 10481f1..7e61b58 100644
--- a/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/internal/MetaRangeClientImpl.java
+++ b/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/internal/MetaRangeClientImpl.java
@@ -78,10 +78,8 @@ class MetaRangeClientImpl implements MetaRangeClient {
     @Override
     public CompletableFuture<HashStreamRanges> getActiveDataRanges() {
         return MetaRangeRequestProcessor.of(
-            createGetActiveRangesRequest(
-                scClient.getStorageContainerId(),
-                streamProps),
-            (response) -> createActiveRanges(response.getGetActiveRangesResp()),
+            createGetActiveRangesRequest(streamProps),
+            (response) -> createActiveRanges(response),
             scClient,
             executor,
             backoffPolicy
diff --git a/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/internal/mr/MetaRangeRequestProcessor.java b/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/internal/mr/MetaRangeRequestProcessor.java
index cb25e84..39e9a5a 100644
--- a/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/internal/mr/MetaRangeRequestProcessor.java
+++ b/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/internal/mr/MetaRangeRequestProcessor.java
@@ -21,37 +21,36 @@ package org.apache.bookkeeper.clients.impl.internal.mr;
 import static org.apache.bookkeeper.clients.impl.internal.ProtocolInternalUtils.createMetaRangeException;
 
 import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.SettableFuture;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.function.Function;
 import org.apache.bookkeeper.clients.impl.channel.StorageServerChannel;
 import org.apache.bookkeeper.clients.impl.container.StorageContainerChannel;
 import org.apache.bookkeeper.clients.utils.ListenableFutureRpcProcessor;
 import org.apache.bookkeeper.common.util.Backoff;
+import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesRequest;
+import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesResponse;
 import org.apache.bookkeeper.stream.proto.storage.StatusCode;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
 
 /**
  * Request Processor processing meta range request.
  */
 public class MetaRangeRequestProcessor<RespT>
-    extends ListenableFutureRpcProcessor<StorageContainerRequest, StorageContainerResponse, RespT> {
+    extends ListenableFutureRpcProcessor<GetActiveRangesRequest, GetActiveRangesResponse, RespT> {
 
     public static <T> MetaRangeRequestProcessor<T> of(
-        StorageContainerRequest request,
-        Function<StorageContainerResponse, T> responseFunc,
+        GetActiveRangesRequest request,
+        Function<GetActiveRangesResponse, T> responseFunc,
         StorageContainerChannel channel,
         ScheduledExecutorService executor,
         Backoff.Policy backoffPolicy) {
         return new MetaRangeRequestProcessor<>(request, responseFunc, channel, executor, backoffPolicy);
     }
 
-    private final StorageContainerRequest request;
-    private final Function<StorageContainerResponse, RespT> responseFunc;
+    private final GetActiveRangesRequest request;
+    private final Function<GetActiveRangesResponse, RespT> responseFunc;
 
-    private MetaRangeRequestProcessor(StorageContainerRequest request,
-                                      Function<StorageContainerResponse, RespT> responseFunc,
+    private MetaRangeRequestProcessor(GetActiveRangesRequest request,
+                                      Function<GetActiveRangesResponse, RespT> responseFunc,
                                       StorageContainerChannel channel,
                                       ScheduledExecutorService executor,
                                       Backoff.Policy backoffPolicy) {
@@ -61,34 +60,23 @@ public class MetaRangeRequestProcessor<RespT>
     }
 
     @Override
-    protected StorageContainerRequest createRequest() {
+    protected GetActiveRangesRequest createRequest() {
         return request;
     }
 
     @Override
-    protected ListenableFuture<StorageContainerResponse> sendRPC(StorageServerChannel rsChannel,
-                                                                 StorageContainerRequest request) {
-        switch (request.getRequestCase()) {
-            case GET_ACTIVE_RANGES_REQ:
-                return rsChannel.getMetaRangeService().getActiveRanges(request);
-            default:
-                SettableFuture<StorageContainerResponse> respFuture = SettableFuture.create();
-                respFuture.setException(new Exception("Unknown request " + request));
-                return respFuture;
-        }
+    protected ListenableFuture<GetActiveRangesResponse> sendRPC(StorageServerChannel rsChannel,
+                                                                GetActiveRangesRequest request) {
+        return rsChannel.getMetaRangeService().getActiveRanges(request);
     }
 
-    private String getIdentifier(StorageContainerRequest request) {
-        switch (request.getRequestCase()) {
-            case GET_ACTIVE_RANGES_REQ:
-                return "" + request.getGetActiveRangesReq().getStreamId();
-            default:
-                return "";
-        }
+    private String getIdentifier(GetActiveRangesRequest request) {
+
+        return "" + request.getStreamId();
     }
 
     @Override
-    protected RespT processResponse(StorageContainerResponse response) throws Exception {
+    protected RespT processResponse(GetActiveRangesResponse response) throws Exception {
         if (StatusCode.SUCCESS == response.getCode()) {
             return responseFunc.apply(response);
         }
diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestMetaRangeClientImpl.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestMetaRangeClientImpl.java
index 189b849..9716162 100644
--- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestMetaRangeClientImpl.java
+++ b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestMetaRangeClientImpl.java
@@ -45,13 +45,12 @@ import org.apache.bookkeeper.common.util.OrderedScheduler;
 import org.apache.bookkeeper.stream.proto.RangeProperties;
 import org.apache.bookkeeper.stream.proto.StreamConfiguration;
 import org.apache.bookkeeper.stream.proto.StreamProperties;
+import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesRequest;
 import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesResponse;
 import org.apache.bookkeeper.stream.proto.storage.MetaRangeServiceGrpc.MetaRangeServiceImplBase;
 import org.apache.bookkeeper.stream.proto.storage.RelatedRanges;
 import org.apache.bookkeeper.stream.proto.storage.RelationType;
 import org.apache.bookkeeper.stream.proto.storage.StatusCode;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
 import org.junit.Test;
 
 /**
@@ -129,21 +128,18 @@ public class TestMetaRangeClientImpl extends GrpcClientTestBase {
 
         // create response
         GetActiveRangesResponse getActiveRangesResponse = GetActiveRangesResponse.newBuilder()
+            .setCode(StatusCode.SUCCESS)
             .addRanges(
                 buildRelatedRange(Long.MIN_VALUE, 0L, 123L, 1L, Lists.newArrayList(113L))
             ).addRanges(
                 buildRelatedRange(0L, Long.MAX_VALUE, 124L, 2L, Lists.newArrayList(114L))
             ).build();
-        StorageContainerResponse response = StorageContainerResponse.newBuilder()
-            .setCode(StatusCode.SUCCESS)
-            .setGetActiveRangesResp(getActiveRangesResponse)
-            .build();
 
         MetaRangeServiceImplBase metaRangeService = new MetaRangeServiceImplBase() {
             @Override
-            public void getActiveRanges(StorageContainerRequest request,
-                                        StreamObserver<StorageContainerResponse> responseObserver) {
-                responseObserver.onNext(response);
+            public void getActiveRanges(GetActiveRangesRequest request,
+                                        StreamObserver<GetActiveRangesResponse> responseObserver) {
+                responseObserver.onNext(getActiveRangesResponse);
                 responseObserver.onCompleted();
             }
         };
@@ -154,7 +150,7 @@ public class TestMetaRangeClientImpl extends GrpcClientTestBase {
             Optional.empty());
         serviceFuture.complete(rsChannel);
 
-        HashStreamRanges expectedStream = createActiveRanges(response.getGetActiveRangesResp());
+        HashStreamRanges expectedStream = createActiveRanges(getActiveRangesResponse);
         CompletableFuture<HashStreamRanges> getFuture = metaRangeClient.getActiveDataRanges();
         assertEquals(expectedStream, getFuture.get());
     }
@@ -166,8 +162,8 @@ public class TestMetaRangeClientImpl extends GrpcClientTestBase {
 
         MetaRangeServiceImplBase metaRangeService = new MetaRangeServiceImplBase() {
             @Override
-            public void getActiveRanges(StorageContainerRequest request,
-                                        StreamObserver<StorageContainerResponse> responseObserver) {
+            public void getActiveRanges(GetActiveRangesRequest request,
+                                        StreamObserver<GetActiveRangesResponse> responseObserver) {
                 responseObserver.onError(new StatusRuntimeException(Status.INTERNAL));
             }
         };
diff --git a/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/DeleteRequestProcessor.java b/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/DeleteRequestProcessor.java
new file mode 100644
index 0000000..88287df
--- /dev/null
+++ b/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/DeleteRequestProcessor.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.bookkeeper.clients.impl.kv;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.function.Function;
+import org.apache.bookkeeper.clients.exceptions.InternalServerException;
+import org.apache.bookkeeper.clients.impl.channel.StorageServerChannel;
+import org.apache.bookkeeper.clients.impl.container.StorageContainerChannel;
+import org.apache.bookkeeper.clients.utils.ListenableFutureRpcProcessor;
+import org.apache.bookkeeper.common.util.Backoff.Policy;
+import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeResponse;
+import org.apache.bookkeeper.stream.proto.storage.StatusCode;
+
+/**
+ * Request Processor processing table request.
+ */
+class DeleteRequestProcessor<RespT>
+    extends ListenableFutureRpcProcessor<DeleteRangeRequest, DeleteRangeResponse, RespT> {
+
+    public static <T> DeleteRequestProcessor<T> of(
+        DeleteRangeRequest request,
+        Function<DeleteRangeResponse, T> responseFunc,
+        StorageContainerChannel channel,
+        ScheduledExecutorService executor,
+        Policy backoffPolicy) {
+        return new DeleteRequestProcessor<>(request, responseFunc, channel, executor, backoffPolicy);
+    }
+
+    private final DeleteRangeRequest request;
+    private final Function<DeleteRangeResponse, RespT> responseFunc;
+
+    private DeleteRequestProcessor(DeleteRangeRequest request,
+                                   Function<DeleteRangeResponse, RespT> respFunc,
+                                   StorageContainerChannel channel,
+                                   ScheduledExecutorService executor,
+                                   Policy backoffPolicy) {
+        super(channel, executor, backoffPolicy);
+        this.request = request;
+        this.responseFunc = respFunc;
+    }
+
+    @Override
+    protected DeleteRangeRequest createRequest() {
+        return request;
+    }
+
+    @Override
+    protected ListenableFuture<DeleteRangeResponse> sendRPC(StorageServerChannel rsChannel,
+                                                            DeleteRangeRequest request) {
+        return rsChannel.getTableService().delete(request);
+    }
+
+    @Override
+    protected RespT processResponse(DeleteRangeResponse response) throws Exception {
+        if (StatusCode.SUCCESS == response.getHeader().getCode()) {
+            return responseFunc.apply(response);
+        }
+        throw new InternalServerException("Encountered internal server exception : code = "
+            + response.getHeader().getCode());
+    }
+}
diff --git a/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/IncrementRequestProcessor.java b/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/IncrementRequestProcessor.java
new file mode 100644
index 0000000..f41c97b
--- /dev/null
+++ b/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/IncrementRequestProcessor.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.bookkeeper.clients.impl.kv;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.function.Function;
+import org.apache.bookkeeper.clients.exceptions.InternalServerException;
+import org.apache.bookkeeper.clients.impl.channel.StorageServerChannel;
+import org.apache.bookkeeper.clients.impl.container.StorageContainerChannel;
+import org.apache.bookkeeper.clients.utils.ListenableFutureRpcProcessor;
+import org.apache.bookkeeper.common.util.Backoff.Policy;
+import org.apache.bookkeeper.stream.proto.kv.rpc.IncrementRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.IncrementResponse;
+import org.apache.bookkeeper.stream.proto.storage.StatusCode;
+
+/**
+ * Request Processor processing table request.
+ */
+class IncrementRequestProcessor<RespT>
+    extends ListenableFutureRpcProcessor<IncrementRequest, IncrementResponse, RespT> {
+
+    public static <T> IncrementRequestProcessor<T> of(
+        IncrementRequest request,
+        Function<IncrementResponse, T> responseFunc,
+        StorageContainerChannel channel,
+        ScheduledExecutorService executor,
+        Policy backoffPolicy) {
+        return new IncrementRequestProcessor<>(request, responseFunc, channel, executor, backoffPolicy);
+    }
+
+    private final IncrementRequest request;
+    private final Function<IncrementResponse, RespT> responseFunc;
+
+    private IncrementRequestProcessor(IncrementRequest request,
+                                      Function<IncrementResponse, RespT> respFunc,
+                                      StorageContainerChannel channel,
+                                      ScheduledExecutorService executor,
+                                      Policy backoffPolicy) {
+        super(channel, executor, backoffPolicy);
+        this.request = request;
+        this.responseFunc = respFunc;
+    }
+
+    @Override
+    protected IncrementRequest createRequest() {
+        return request;
+    }
+
+    @Override
+    protected ListenableFuture<IncrementResponse> sendRPC(StorageServerChannel rsChannel,
+                                                          IncrementRequest request) {
+        return rsChannel.getTableService().increment(request);
+    }
+
+    @Override
+    protected RespT processResponse(IncrementResponse response) throws Exception {
+        if (StatusCode.SUCCESS == response.getHeader().getCode()) {
+            return responseFunc.apply(response);
+        }
+        throw new InternalServerException("Encountered internal server exception : code = "
+            + response.getHeader().getCode());
+    }
+}
diff --git a/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/KvUtils.java b/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/KvUtils.java
index 2fd27ce..279219b 100644
--- a/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/KvUtils.java
+++ b/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/KvUtils.java
@@ -52,9 +52,7 @@ import org.apache.bookkeeper.stream.proto.kv.rpc.PutResponse;
 import org.apache.bookkeeper.stream.proto.kv.rpc.RangeRequest;
 import org.apache.bookkeeper.stream.proto.kv.rpc.RangeResponse;
 import org.apache.bookkeeper.stream.proto.kv.rpc.RequestOp;
-import org.apache.bookkeeper.stream.proto.kv.rpc.TxnRequest;
 import org.apache.bookkeeper.stream.proto.kv.rpc.TxnResponse;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
 
 /**
  * K/V related utils.
@@ -86,15 +84,6 @@ public final class KvUtils {
         return Lists.transform(kvs, kv -> fromProtoKeyValue(kv, kvFactory));
     }
 
-    public static StorageContainerRequest newKvRangeRequest(
-        long scId,
-        RangeRequest.Builder rangeReq) {
-        return StorageContainerRequest.newBuilder()
-            .setScId(scId)
-            .setKvRangeReq(rangeReq)
-            .build();
-    }
-
     public static RangeRequest.Builder newRangeRequest(ByteBuf key, RangeOption<ByteBuf> option) {
         RangeRequest.Builder builder = RangeRequest.newBuilder()
             .setKey(toProtoKey(key))
@@ -121,15 +110,6 @@ public final class KvUtils {
             .kvs(fromProtoKeyValues(response.getKvsList(), kvFactory));
     }
 
-    public static StorageContainerRequest newKvPutRequest(
-        long scId,
-        PutRequest.Builder putReq) {
-        return StorageContainerRequest.newBuilder()
-            .setScId(scId)
-            .setKvPutReq(putReq)
-            .build();
-    }
-
     public static PutRequest.Builder newPutRequest(ByteBuf key,
                                                    ByteBuf value,
                                                    PutOption<ByteBuf> option) {
@@ -150,15 +130,6 @@ public final class KvUtils {
         return result;
     }
 
-    public static StorageContainerRequest newKvIncrementRequest(
-        long scId,
-        IncrementRequest.Builder putReq) {
-        return StorageContainerRequest.newBuilder()
-            .setScId(scId)
-            .setKvIncrReq(putReq)
-            .build();
-    }
-
     public static IncrementRequest.Builder newIncrementRequest(ByteBuf key,
                                                                long amount,
                                                                IncrementOption<ByteBuf> option) {
@@ -177,15 +148,6 @@ public final class KvUtils {
         return result;
     }
 
-    public static StorageContainerRequest newKvDeleteRequest(
-        long scId,
-        DeleteRangeRequest.Builder deleteReq) {
-        return StorageContainerRequest.newBuilder()
-            .setScId(scId)
-            .setKvDeleteReq(deleteReq)
-            .build();
-    }
-
     public static DeleteRangeRequest.Builder newDeleteRequest(ByteBuf key, DeleteOption<ByteBuf> option) {
         DeleteRangeRequest.Builder builder = DeleteRangeRequest.newBuilder()
             .setKey(UnsafeByteOperations.unsafeWrap(key.nioBuffer()))
@@ -310,15 +272,6 @@ public final class KvUtils {
         return reqBuilder;
     }
 
-    public static StorageContainerRequest newKvTxnRequest(
-        long scId,
-        TxnRequest.Builder txnReq) {
-        return StorageContainerRequest.newBuilder()
-            .setScId(scId)
-            .setKvTxnReq(txnReq)
-            .build();
-    }
-
     public static TxnResult<ByteBuf, ByteBuf> newKvTxnResult(
         TxnResponse txnResponse,
         ResultFactory<ByteBuf, ByteBuf> resultFactory,
diff --git a/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/PByteBufTableRangeImpl.java b/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/PByteBufTableRangeImpl.java
index 03c64f7..1f07b80 100644
--- a/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/PByteBufTableRangeImpl.java
+++ b/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/PByteBufTableRangeImpl.java
@@ -94,12 +94,11 @@ class PByteBufTableRangeImpl implements PTable<ByteBuf, ByteBuf> {
         if (null != option.endKey()) {
             option.endKey().retain();
         }
-        return TableRequestProcessor.of(
-            KvUtils.newKvRangeRequest(
-                scChannel.getStorageContainerId(),
-                KvUtils.newRangeRequest(lKey, option)
-                    .setHeader(newRoutingHeader(pKey))),
-            response -> KvUtils.newRangeResult(response.getKvRangeResp(), resultFactory, kvFactory),
+        return RangeRequestProcessor.of(
+            KvUtils.newRangeRequest(lKey, option)
+                .setHeader(newRoutingHeader(pKey))
+                .build(),
+            response -> KvUtils.newRangeResult(response, resultFactory, kvFactory),
             scChannel,
             executor,
             backoffPolicy
@@ -120,12 +119,11 @@ class PByteBufTableRangeImpl implements PTable<ByteBuf, ByteBuf> {
         pKey.retain();
         lKey.retain();
         value.retain();
-        return TableRequestProcessor.of(
-            KvUtils.newKvPutRequest(
-                scChannel.getStorageContainerId(),
-                KvUtils.newPutRequest(lKey, value, option)
-                    .setHeader(newRoutingHeader(pKey))),
-            response -> KvUtils.newPutResult(response.getKvPutResp(), resultFactory, kvFactory),
+        return PutRequestProcessor.of(
+            KvUtils.newPutRequest(lKey, value, option)
+                .setHeader(newRoutingHeader(pKey))
+                .build(),
+            response -> KvUtils.newPutResult(response, resultFactory, kvFactory),
             scChannel,
             executor,
             backoffPolicy
@@ -145,12 +143,11 @@ class PByteBufTableRangeImpl implements PTable<ByteBuf, ByteBuf> {
         if (null != option.endKey()) {
             option.endKey().retain();
         }
-        return TableRequestProcessor.of(
-            KvUtils.newKvDeleteRequest(
-                scChannel.getStorageContainerId(),
-                KvUtils.newDeleteRequest(lKey, option)
-                    .setHeader(newRoutingHeader(pKey))),
-            response -> KvUtils.newDeleteResult(response.getKvDeleteResp(), resultFactory, kvFactory),
+        return DeleteRequestProcessor.of(
+            KvUtils.newDeleteRequest(lKey, option)
+                .setHeader(newRoutingHeader(pKey))
+                .build(),
+            response -> KvUtils.newDeleteResult(response, resultFactory, kvFactory),
             scChannel,
             executor,
             backoffPolicy
@@ -170,12 +167,11 @@ class PByteBufTableRangeImpl implements PTable<ByteBuf, ByteBuf> {
                                                                           IncrementOption<ByteBuf> option) {
         pKey.retain();
         lKey.retain();
-        return TableRequestProcessor.of(
-            KvUtils.newKvIncrementRequest(
-                scChannel.getStorageContainerId(),
-                KvUtils.newIncrementRequest(lKey, amount, option)
-                    .setHeader(newRoutingHeader(pKey))),
-            response -> KvUtils.newIncrementResult(response.getKvIncrResp(), resultFactory, kvFactory),
+        return IncrementRequestProcessor.of(
+            KvUtils.newIncrementRequest(lKey, amount, option)
+                .setHeader(newRoutingHeader(pKey))
+                .build(),
+            response -> KvUtils.newIncrementResult(response, resultFactory, kvFactory),
             scChannel,
             executor,
             backoffPolicy
@@ -248,11 +244,9 @@ class PByteBufTableRangeImpl implements PTable<ByteBuf, ByteBuf> {
 
         @Override
         public CompletableFuture<TxnResult<ByteBuf, ByteBuf>> commit() {
-            return TableRequestProcessor.of(
-                KvUtils.newKvTxnRequest(
-                    scChannel.getStorageContainerId(),
-                    txnBuilder.setHeader(newRoutingHeader(pKey))),
-                response -> KvUtils.newKvTxnResult(response.getKvTxnResp(), resultFactory, kvFactory),
+            return TxnRequestProcessor.of(
+                txnBuilder.setHeader(newRoutingHeader(pKey)).build(),
+                response -> KvUtils.newKvTxnResult(response, resultFactory, kvFactory),
                 scChannel,
                 executor,
                 backoffPolicy
diff --git a/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/PutRequestProcessor.java b/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/PutRequestProcessor.java
new file mode 100644
index 0000000..38ae6fc
--- /dev/null
+++ b/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/PutRequestProcessor.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.bookkeeper.clients.impl.kv;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.function.Function;
+import org.apache.bookkeeper.clients.exceptions.InternalServerException;
+import org.apache.bookkeeper.clients.impl.channel.StorageServerChannel;
+import org.apache.bookkeeper.clients.impl.container.StorageContainerChannel;
+import org.apache.bookkeeper.clients.utils.ListenableFutureRpcProcessor;
+import org.apache.bookkeeper.common.util.Backoff.Policy;
+import org.apache.bookkeeper.stream.proto.kv.rpc.PutRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.PutResponse;
+import org.apache.bookkeeper.stream.proto.storage.StatusCode;
+
+/**
+ * Request Processor processing table request.
+ */
+class PutRequestProcessor<RespT>
+    extends ListenableFutureRpcProcessor<PutRequest, PutResponse, RespT> {
+
+    public static <T> PutRequestProcessor<T> of(
+        PutRequest request,
+        Function<PutResponse, T> responseFunc,
+        StorageContainerChannel channel,
+        ScheduledExecutorService executor,
+        Policy backoffPolicy) {
+        return new PutRequestProcessor<>(request, responseFunc, channel, executor, backoffPolicy);
+    }
+
+    private final PutRequest request;
+    private final Function<PutResponse, RespT> responseFunc;
+
+    private PutRequestProcessor(PutRequest request,
+                                Function<PutResponse, RespT> respFunc,
+                                StorageContainerChannel channel,
+                                ScheduledExecutorService executor,
+                                Policy backoffPolicy) {
+        super(channel, executor, backoffPolicy);
+        this.request = request;
+        this.responseFunc = respFunc;
+    }
+
+    @Override
+    protected PutRequest createRequest() {
+        return request;
+    }
+
+    @Override
+    protected ListenableFuture<PutResponse> sendRPC(StorageServerChannel rsChannel,
+                                                    PutRequest request) {
+        return rsChannel.getTableService().put(request);
+    }
+
+    @Override
+    protected RespT processResponse(PutResponse response) throws Exception {
+        if (StatusCode.SUCCESS == response.getHeader().getCode()) {
+            return responseFunc.apply(response);
+        }
+        throw new InternalServerException("Encountered internal server exception : code = "
+            + response.getHeader().getCode());
+    }
+}
diff --git a/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/RangeRequestProcessor.java b/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/RangeRequestProcessor.java
new file mode 100644
index 0000000..de2ac87
--- /dev/null
+++ b/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/RangeRequestProcessor.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.bookkeeper.clients.impl.kv;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.function.Function;
+import org.apache.bookkeeper.clients.exceptions.InternalServerException;
+import org.apache.bookkeeper.clients.impl.channel.StorageServerChannel;
+import org.apache.bookkeeper.clients.impl.container.StorageContainerChannel;
+import org.apache.bookkeeper.clients.utils.ListenableFutureRpcProcessor;
+import org.apache.bookkeeper.common.util.Backoff.Policy;
+import org.apache.bookkeeper.stream.proto.kv.rpc.RangeRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.RangeResponse;
+import org.apache.bookkeeper.stream.proto.storage.StatusCode;
+
+/**
+ * Request Processor processing table request.
+ */
+class RangeRequestProcessor<RespT>
+    extends ListenableFutureRpcProcessor<RangeRequest, RangeResponse, RespT> {
+
+    public static <T> RangeRequestProcessor<T> of(
+        RangeRequest request,
+        Function<RangeResponse, T> responseFunc,
+        StorageContainerChannel channel,
+        ScheduledExecutorService executor,
+        Policy backoffPolicy) {
+        return new RangeRequestProcessor<>(request, responseFunc, channel, executor, backoffPolicy);
+    }
+
+    private final RangeRequest request;
+    private final Function<RangeResponse, RespT> responseFunc;
+
+    private RangeRequestProcessor(RangeRequest request,
+                                  Function<RangeResponse, RespT> respFunc,
+                                  StorageContainerChannel channel,
+                                  ScheduledExecutorService executor,
+                                  Policy backoffPolicy) {
+        super(channel, executor, backoffPolicy);
+        this.request = request;
+        this.responseFunc = respFunc;
+    }
+
+    @Override
+    protected RangeRequest createRequest() {
+        return request;
+    }
+
+    @Override
+    protected ListenableFuture<RangeResponse> sendRPC(StorageServerChannel rsChannel,
+                                                      RangeRequest request) {
+        return rsChannel.getTableService().range(request);
+    }
+
+    @Override
+    protected RespT processResponse(RangeResponse response) throws Exception {
+        if (StatusCode.SUCCESS == response.getHeader().getCode()) {
+            return responseFunc.apply(response);
+        }
+        throw new InternalServerException("Encountered internal server exception : code = "
+            + response.getHeader().getCode());
+    }
+}
diff --git a/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/TableRequestProcessor.java b/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/TableRequestProcessor.java
deleted file mode 100644
index f5e0bc5..0000000
--- a/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/TableRequestProcessor.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.bookkeeper.clients.impl.kv;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.SettableFuture;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.function.Function;
-import java.util.stream.Stream;
-import org.apache.bookkeeper.clients.exceptions.InternalServerException;
-import org.apache.bookkeeper.clients.impl.channel.StorageServerChannel;
-import org.apache.bookkeeper.clients.impl.container.StorageContainerChannel;
-import org.apache.bookkeeper.clients.utils.ListenableFutureRpcProcessor;
-import org.apache.bookkeeper.common.util.Backoff.Policy;
-import org.apache.bookkeeper.stream.proto.storage.StatusCode;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
-
-/**
- * Request Processor processing table request.
- */
-public class TableRequestProcessor<RespT>
-    extends ListenableFutureRpcProcessor<StorageContainerRequest, StorageContainerResponse, RespT> {
-
-    public static <T> TableRequestProcessor<T> of(
-        StorageContainerRequest request,
-        Function<StorageContainerResponse, T> responseFunc,
-        StorageContainerChannel channel,
-        ScheduledExecutorService executor,
-        Policy backoffPolicy) {
-        return new TableRequestProcessor<>(request, responseFunc, channel, executor, backoffPolicy);
-    }
-
-    private final StorageContainerRequest request;
-    private final Function<StorageContainerResponse, RespT> responseFunc;
-
-    private TableRequestProcessor(StorageContainerRequest request,
-                                  Function<StorageContainerResponse, RespT> respFunc,
-                                  StorageContainerChannel channel,
-                                  ScheduledExecutorService executor,
-                                  Policy backoffPolicy) {
-        super(channel, executor, backoffPolicy);
-        this.request = request;
-        this.responseFunc = respFunc;
-    }
-
-    @Override
-    protected StorageContainerRequest createRequest() {
-        return request;
-    }
-
-    @Override
-    protected ListenableFuture<StorageContainerResponse> sendRPC(StorageServerChannel rsChannel,
-                                                                 StorageContainerRequest request) {
-        switch (request.getRequestCase()) {
-            case KV_RANGE_REQ:
-                return rsChannel.getTableService().range(request);
-            case KV_PUT_REQ:
-                return rsChannel.getTableService().put(request);
-            case KV_DELETE_REQ:
-                return rsChannel.getTableService().delete(request);
-            case KV_INCR_REQ:
-                return rsChannel.getTableService().increment(request);
-            case KV_TXN_REQ:
-                return rsChannel.getTableService().txn(request);
-            default:
-                SettableFuture<StorageContainerResponse> respFuture = SettableFuture.create();
-                respFuture.setException(new Exception("Unknown request " + request));
-                return respFuture;
-        }
-    }
-
-    @Override
-    protected RespT processResponse(StorageContainerResponse response) throws Exception {
-        if (StatusCode.SUCCESS == response.getCode()) {
-            return responseFunc.apply(response);
-        }
-        throw new InternalServerException("Encountered internal server exception : code = "
-            + response.getCode());
-    }
-}
diff --git a/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/TxnRequestProcessor.java b/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/TxnRequestProcessor.java
new file mode 100644
index 0000000..a3ed209
--- /dev/null
+++ b/stream/clients/java/kv/src/main/java/org/apache/bookkeeper/clients/impl/kv/TxnRequestProcessor.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.bookkeeper.clients.impl.kv;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.function.Function;
+import org.apache.bookkeeper.clients.exceptions.InternalServerException;
+import org.apache.bookkeeper.clients.impl.channel.StorageServerChannel;
+import org.apache.bookkeeper.clients.impl.container.StorageContainerChannel;
+import org.apache.bookkeeper.clients.utils.ListenableFutureRpcProcessor;
+import org.apache.bookkeeper.common.util.Backoff.Policy;
+import org.apache.bookkeeper.stream.proto.kv.rpc.TxnRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.TxnResponse;
+import org.apache.bookkeeper.stream.proto.storage.StatusCode;
+
+/**
+ * Request Processor processing table request.
+ */
+class TxnRequestProcessor<RespT>
+    extends ListenableFutureRpcProcessor<TxnRequest, TxnResponse, RespT> {
+
+    public static <T> TxnRequestProcessor<T> of(
+        TxnRequest request,
+        Function<TxnResponse, T> responseFunc,
+        StorageContainerChannel channel,
+        ScheduledExecutorService executor,
+        Policy backoffPolicy) {
+        return new TxnRequestProcessor<>(request, responseFunc, channel, executor, backoffPolicy);
+    }
+
+    private final TxnRequest request;
+    private final Function<TxnResponse, RespT> responseFunc;
+
+    private TxnRequestProcessor(TxnRequest request,
+                                Function<TxnResponse, RespT> respFunc,
+                                StorageContainerChannel channel,
+                                ScheduledExecutorService executor,
+                                Policy backoffPolicy) {
+        super(channel, executor, backoffPolicy);
+        this.request = request;
+        this.responseFunc = respFunc;
+    }
+
+    @Override
+    protected TxnRequest createRequest() {
+        return request;
+    }
+
+    @Override
+    protected ListenableFuture<TxnResponse> sendRPC(StorageServerChannel rsChannel,
+                                                    TxnRequest request) {
+        return rsChannel.getTableService().txn(request);
+    }
+
+    @Override
+    protected RespT processResponse(TxnResponse response) throws Exception {
+        if (StatusCode.SUCCESS == response.getHeader().getCode()) {
+            return responseFunc.apply(response);
+        }
+        throw new InternalServerException("Encountered internal server exception : code = "
+            + response.getHeader().getCode());
+    }
+}
diff --git a/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/DeleteRequestProcessorTest.java b/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/DeleteRequestProcessorTest.java
new file mode 100644
index 0000000..8b01b9b
--- /dev/null
+++ b/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/DeleteRequestProcessorTest.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.bookkeeper.clients.impl.kv;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import io.grpc.inprocess.InProcessChannelBuilder;
+import io.grpc.stub.StreamObserver;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.atomic.AtomicReference;
+import lombok.Cleanup;
+import org.apache.bookkeeper.clients.grpc.GrpcClientTestBase;
+import org.apache.bookkeeper.clients.impl.channel.StorageServerChannel;
+import org.apache.bookkeeper.clients.impl.container.StorageContainerChannel;
+import org.apache.bookkeeper.clients.utils.ClientConstants;
+import org.apache.bookkeeper.common.concurrent.FutureUtils;
+import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeResponse;
+import org.apache.bookkeeper.stream.proto.kv.rpc.ResponseHeader;
+import org.apache.bookkeeper.stream.proto.kv.rpc.TableServiceGrpc.TableServiceImplBase;
+import org.apache.bookkeeper.stream.proto.storage.StatusCode;
+import org.junit.Test;
+
+/**
+ * Unit test of {@link DeleteRequestProcessor}.
+ */
+public class DeleteRequestProcessorTest extends GrpcClientTestBase {
+
+    @Override
+    protected void doSetup() throws Exception {
+    }
+
+    @Override
+    protected void doTeardown() throws Exception {
+    }
+
+    protected DeleteRangeResponse newSuccessResponse() {
+        return DeleteRangeResponse.newBuilder()
+            .setHeader(ResponseHeader.newBuilder()
+                .setCode(StatusCode.SUCCESS)
+                .build())
+            .build();
+    }
+
+    protected DeleteRangeRequest newRequest() {
+        return DeleteRangeRequest.newBuilder()
+            .build();
+    }
+
+    @Test
+    public void testProcess() throws Exception {
+        @Cleanup("shutdown") ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
+
+        StorageContainerChannel scChannel = mock(StorageContainerChannel.class);
+
+        CompletableFuture<StorageServerChannel> serverChannelFuture = FutureUtils.createFuture();
+        when(scChannel.getStorageContainerChannelFuture()).thenReturn(serverChannelFuture);
+
+        DeleteRangeResponse response = newSuccessResponse();
+
+        AtomicReference<Object> receivedRequest = new AtomicReference<>(null);
+        TableServiceImplBase tableService = new TableServiceImplBase() {
+
+            @Override
+            public void delete(DeleteRangeRequest request,
+                               StreamObserver<DeleteRangeResponse> responseObserver) {
+                receivedRequest.set(request);
+                complete(responseObserver);
+            }
+
+            private void complete(StreamObserver<DeleteRangeResponse> responseStreamObserver) {
+                responseStreamObserver.onNext(response);
+                responseStreamObserver.onCompleted();
+            }
+        };
+        serviceRegistry.addService(tableService.bindService());
+        StorageServerChannel ssChannel = new StorageServerChannel(
+            InProcessChannelBuilder.forName(serverName).directExecutor().build(),
+            Optional.empty());
+        serverChannelFuture.complete(ssChannel);
+
+        DeleteRangeRequest request = newRequest();
+
+        DeleteRequestProcessor<String> processor = DeleteRequestProcessor.of(
+            request,
+            resp -> "test",
+            scChannel,
+            scheduler,
+            ClientConstants.DEFAULT_INFINIT_BACKOFF_POLICY);
+        assertEquals("test", FutureUtils.result(processor.process()));
+        assertSame(request, receivedRequest.get());
+    }
+
+}
diff --git a/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/IncrementRequestProcessorTest.java b/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/IncrementRequestProcessorTest.java
new file mode 100644
index 0000000..1b1ec49
--- /dev/null
+++ b/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/IncrementRequestProcessorTest.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.bookkeeper.clients.impl.kv;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import io.grpc.inprocess.InProcessChannelBuilder;
+import io.grpc.stub.StreamObserver;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.atomic.AtomicReference;
+import lombok.Cleanup;
+import org.apache.bookkeeper.clients.grpc.GrpcClientTestBase;
+import org.apache.bookkeeper.clients.impl.channel.StorageServerChannel;
+import org.apache.bookkeeper.clients.impl.container.StorageContainerChannel;
+import org.apache.bookkeeper.clients.utils.ClientConstants;
+import org.apache.bookkeeper.common.concurrent.FutureUtils;
+import org.apache.bookkeeper.stream.proto.kv.rpc.IncrementRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.IncrementResponse;
+import org.apache.bookkeeper.stream.proto.kv.rpc.ResponseHeader;
+import org.apache.bookkeeper.stream.proto.kv.rpc.TableServiceGrpc.TableServiceImplBase;
+import org.apache.bookkeeper.stream.proto.storage.StatusCode;
+import org.junit.Test;
+
+/**
+ * Unit test of {@link IncrementRequestProcessor}.
+ */
+public class IncrementRequestProcessorTest extends GrpcClientTestBase {
+
+    @Override
+    protected void doSetup() throws Exception {
+    }
+
+    @Override
+    protected void doTeardown() throws Exception {
+    }
+
+    protected IncrementResponse newSuccessResponse() {
+        return IncrementResponse.newBuilder()
+            .setHeader(ResponseHeader.newBuilder()
+                .setCode(StatusCode.SUCCESS)
+                .build())
+            .build();
+    }
+
+    protected IncrementRequest newRequest() {
+        return IncrementRequest.newBuilder()
+            .build();
+    }
+
+    @Test
+    public void testProcess() throws Exception {
+        @Cleanup("shutdown") ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
+
+        StorageContainerChannel scChannel = mock(StorageContainerChannel.class);
+
+        CompletableFuture<StorageServerChannel> serverChannelFuture = FutureUtils.createFuture();
+        when(scChannel.getStorageContainerChannelFuture()).thenReturn(serverChannelFuture);
+
+        IncrementResponse response = newSuccessResponse();
+
+        AtomicReference<Object> receivedRequest = new AtomicReference<>(null);
+        TableServiceImplBase tableService = new TableServiceImplBase() {
+
+            @Override
+            public void increment(IncrementRequest request,
+                                  StreamObserver<IncrementResponse> responseObserver) {
+                receivedRequest.set(request);
+                complete(responseObserver);
+            }
+
+            private void complete(StreamObserver<IncrementResponse> responseStreamObserver) {
+                responseStreamObserver.onNext(response);
+                responseStreamObserver.onCompleted();
+            }
+        };
+        serviceRegistry.addService(tableService.bindService());
+        StorageServerChannel ssChannel = new StorageServerChannel(
+            InProcessChannelBuilder.forName(serverName).directExecutor().build(),
+            Optional.empty());
+        serverChannelFuture.complete(ssChannel);
+
+        IncrementRequest request = newRequest();
+
+        IncrementRequestProcessor<String> processor = IncrementRequestProcessor.of(
+            request,
+            resp -> "test",
+            scChannel,
+            scheduler,
+            ClientConstants.DEFAULT_INFINIT_BACKOFF_POLICY);
+        assertEquals("test", FutureUtils.result(processor.process()));
+        assertSame(request, receivedRequest.get());
+    }
+
+}
diff --git a/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/PutRequestProcessorTest.java b/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/PutRequestProcessorTest.java
new file mode 100644
index 0000000..3481a26
--- /dev/null
+++ b/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/PutRequestProcessorTest.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.bookkeeper.clients.impl.kv;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import io.grpc.inprocess.InProcessChannelBuilder;
+import io.grpc.stub.StreamObserver;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.atomic.AtomicReference;
+import lombok.Cleanup;
+import org.apache.bookkeeper.clients.grpc.GrpcClientTestBase;
+import org.apache.bookkeeper.clients.impl.channel.StorageServerChannel;
+import org.apache.bookkeeper.clients.impl.container.StorageContainerChannel;
+import org.apache.bookkeeper.clients.utils.ClientConstants;
+import org.apache.bookkeeper.common.concurrent.FutureUtils;
+import org.apache.bookkeeper.stream.proto.kv.rpc.PutRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.PutResponse;
+import org.apache.bookkeeper.stream.proto.kv.rpc.ResponseHeader;
+import org.apache.bookkeeper.stream.proto.kv.rpc.TableServiceGrpc.TableServiceImplBase;
+import org.apache.bookkeeper.stream.proto.storage.StatusCode;
+import org.junit.Test;
+
+/**
+ * Unit test of {@link PutRequestProcessor}.
+ */
+public class PutRequestProcessorTest extends GrpcClientTestBase {
+
+    @Override
+    protected void doSetup() throws Exception {
+    }
+
+    @Override
+    protected void doTeardown() throws Exception {
+    }
+
+    protected PutResponse newSuccessResponse() {
+        return PutResponse.newBuilder()
+            .setHeader(ResponseHeader.newBuilder()
+                .setCode(StatusCode.SUCCESS)
+                .build())
+            .build();
+    }
+
+    protected PutRequest newRequest() {
+        return PutRequest.newBuilder()
+            .build();
+    }
+
+    @Test
+    public void testProcess() throws Exception {
+        @Cleanup("shutdown") ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
+
+        StorageContainerChannel scChannel = mock(StorageContainerChannel.class);
+
+        CompletableFuture<StorageServerChannel> serverChannelFuture = FutureUtils.createFuture();
+        when(scChannel.getStorageContainerChannelFuture()).thenReturn(serverChannelFuture);
+
+        PutResponse response = newSuccessResponse();
+
+        AtomicReference<Object> receivedRequest = new AtomicReference<>(null);
+        TableServiceImplBase tableService = new TableServiceImplBase() {
+
+            @Override
+            public void put(PutRequest request,
+                            StreamObserver<PutResponse> responseObserver) {
+                receivedRequest.set(request);
+                complete(responseObserver);
+            }
+
+            private void complete(StreamObserver<PutResponse> responseStreamObserver) {
+                responseStreamObserver.onNext(response);
+                responseStreamObserver.onCompleted();
+            }
+        };
+        serviceRegistry.addService(tableService.bindService());
+        StorageServerChannel ssChannel = new StorageServerChannel(
+            InProcessChannelBuilder.forName(serverName).directExecutor().build(),
+            Optional.empty());
+        serverChannelFuture.complete(ssChannel);
+
+        PutRequest request = newRequest();
+
+        PutRequestProcessor<String> processor = PutRequestProcessor.of(
+            request,
+            resp -> "test",
+            scChannel,
+            scheduler,
+            ClientConstants.DEFAULT_INFINIT_BACKOFF_POLICY);
+        assertEquals("test", FutureUtils.result(processor.process()));
+        assertSame(request, receivedRequest.get());
+    }
+
+}
diff --git a/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/RangeRequestProcessorTest.java b/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/RangeRequestProcessorTest.java
new file mode 100644
index 0000000..9e53df7
--- /dev/null
+++ b/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/RangeRequestProcessorTest.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.bookkeeper.clients.impl.kv;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import io.grpc.inprocess.InProcessChannelBuilder;
+import io.grpc.stub.StreamObserver;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.atomic.AtomicReference;
+import lombok.Cleanup;
+import org.apache.bookkeeper.clients.grpc.GrpcClientTestBase;
+import org.apache.bookkeeper.clients.impl.channel.StorageServerChannel;
+import org.apache.bookkeeper.clients.impl.container.StorageContainerChannel;
+import org.apache.bookkeeper.clients.utils.ClientConstants;
+import org.apache.bookkeeper.common.concurrent.FutureUtils;
+import org.apache.bookkeeper.stream.proto.kv.rpc.RangeRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.RangeResponse;
+import org.apache.bookkeeper.stream.proto.kv.rpc.ResponseHeader;
+import org.apache.bookkeeper.stream.proto.kv.rpc.TableServiceGrpc.TableServiceImplBase;
+import org.apache.bookkeeper.stream.proto.storage.StatusCode;
+import org.junit.Test;
+
+/**
+ * Unit test of {@link RangeRequestProcessor}.
+ */
+public class RangeRequestProcessorTest extends GrpcClientTestBase {
+
+    @Override
+    protected void doSetup() throws Exception {
+    }
+
+    @Override
+    protected void doTeardown() throws Exception {
+    }
+
+    protected RangeResponse newSuccessResponse() {
+        return RangeResponse.newBuilder()
+            .setHeader(ResponseHeader.newBuilder()
+                .setCode(StatusCode.SUCCESS)
+                .build())
+            .build();
+    }
+
+    protected RangeRequest newRequest() {
+        return RangeRequest.newBuilder()
+            .build();
+    }
+
+    @Test
+    public void testProcess() throws Exception {
+        @Cleanup("shutdown") ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
+
+        StorageContainerChannel scChannel = mock(StorageContainerChannel.class);
+
+        CompletableFuture<StorageServerChannel> serverChannelFuture = FutureUtils.createFuture();
+        when(scChannel.getStorageContainerChannelFuture()).thenReturn(serverChannelFuture);
+
+        RangeResponse response = newSuccessResponse();
+
+        AtomicReference<Object> receivedRequest = new AtomicReference<>(null);
+        TableServiceImplBase tableService = new TableServiceImplBase() {
+
+            @Override
+            public void range(RangeRequest request,
+                              StreamObserver<RangeResponse> responseObserver) {
+                receivedRequest.set(request);
+                complete(responseObserver);
+            }
+
+            private void complete(StreamObserver<RangeResponse> responseStreamObserver) {
+                responseStreamObserver.onNext(response);
+                responseStreamObserver.onCompleted();
+            }
+        };
+        serviceRegistry.addService(tableService.bindService());
+        StorageServerChannel ssChannel = new StorageServerChannel(
+            InProcessChannelBuilder.forName(serverName).directExecutor().build(),
+            Optional.empty());
+        serverChannelFuture.complete(ssChannel);
+
+        RangeRequest request = newRequest();
+
+        RangeRequestProcessor<String> processor = RangeRequestProcessor.of(
+            request,
+            resp -> "test",
+            scChannel,
+            scheduler,
+            ClientConstants.DEFAULT_INFINIT_BACKOFF_POLICY);
+        assertEquals("test", FutureUtils.result(processor.process()));
+        assertSame(request, receivedRequest.get());
+    }
+
+}
diff --git a/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/TableRequestProcessorTest.java b/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/TableRequestProcessorTest.java
deleted file mode 100644
index bec76e5..0000000
--- a/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/TableRequestProcessorTest.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.bookkeeper.clients.impl.kv;
-
-import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_DELETE_REQ;
-import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_INCR_REQ;
-import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_PUT_REQ;
-import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_RANGE_REQ;
-import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_TXN_REQ;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertSame;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import io.grpc.inprocess.InProcessChannelBuilder;
-import io.grpc.stub.StreamObserver;
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.atomic.AtomicReference;
-import lombok.Cleanup;
-import org.apache.bookkeeper.clients.grpc.GrpcClientTestBase;
-import org.apache.bookkeeper.clients.impl.channel.StorageServerChannel;
-import org.apache.bookkeeper.clients.impl.container.StorageContainerChannel;
-import org.apache.bookkeeper.clients.utils.ClientConstants;
-import org.apache.bookkeeper.common.concurrent.FutureUtils;
-import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeRequest;
-import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeResponse;
-import org.apache.bookkeeper.stream.proto.kv.rpc.IncrementRequest;
-import org.apache.bookkeeper.stream.proto.kv.rpc.IncrementResponse;
-import org.apache.bookkeeper.stream.proto.kv.rpc.PutRequest;
-import org.apache.bookkeeper.stream.proto.kv.rpc.PutResponse;
-import org.apache.bookkeeper.stream.proto.kv.rpc.RangeRequest;
-import org.apache.bookkeeper.stream.proto.kv.rpc.RangeResponse;
-import org.apache.bookkeeper.stream.proto.kv.rpc.TxnRequest;
-import org.apache.bookkeeper.stream.proto.kv.rpc.TxnResponse;
-import org.apache.bookkeeper.stream.proto.storage.StatusCode;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
-import org.apache.bookkeeper.stream.proto.storage.TableServiceGrpc.TableServiceImplBase;
-import org.junit.Test;
-
-/**
- * Unit test of {@link TableRequestProcessor}.
- */
-public class TableRequestProcessorTest extends GrpcClientTestBase {
-
-    @Override
-    protected void doSetup() throws Exception {
-    }
-
-    @Override
-    protected void doTeardown() throws Exception {
-    }
-
-    @Test
-    public void testProcessRangeRequest() throws Exception {
-        testProcess(KV_RANGE_REQ);
-    }
-
-    @Test
-    public void testProcessPutRequest() throws Exception {
-        testProcess(KV_PUT_REQ);
-    }
-
-    @Test
-    public void testProcessDeleteRequest() throws Exception {
-        testProcess(KV_DELETE_REQ);
-    }
-
-    @Test
-    public void testProcessIncrementRequest() throws Exception {
-        testProcess(KV_INCR_REQ);
-    }
-
-    @Test
-    public void testProcessTxnRequest() throws Exception {
-        testProcess(KV_TXN_REQ);
-    }
-
-    private void testProcess(RequestCase type) throws Exception {
-        @Cleanup("shutdown") ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
-
-        StorageContainerChannel scChannel = mock(StorageContainerChannel.class);
-
-        CompletableFuture<StorageServerChannel> serverChannelFuture = FutureUtils.createFuture();
-        when(scChannel.getStorageContainerChannelFuture()).thenReturn(serverChannelFuture);
-
-        StorageContainerResponse.Builder respBuilder = StorageContainerResponse.newBuilder()
-            .setCode(StatusCode.SUCCESS);
-
-        switch (type) {
-            case KV_PUT_REQ:
-                respBuilder.setKvPutResp(PutResponse.newBuilder().build());
-                break;
-            case KV_DELETE_REQ:
-                respBuilder.setKvDeleteResp(DeleteRangeResponse.newBuilder().build());
-                break;
-            case KV_RANGE_REQ:
-                respBuilder.setKvRangeResp(RangeResponse.newBuilder().build());
-                break;
-            case KV_INCR_REQ:
-                respBuilder.setKvIncrResp(IncrementResponse.newBuilder().build());
-                break;
-            case KV_TXN_REQ:
-                respBuilder.setKvTxnResp(TxnResponse.newBuilder().build());
-                break;
-            default:
-                break;
-        }
-        StorageContainerResponse response = respBuilder.build();
-
-        AtomicReference<StorageContainerRequest> receivedRequest = new AtomicReference<>(null);
-        AtomicReference<RequestCase> receivedRequestType = new AtomicReference<>(null);
-        TableServiceImplBase tableService = new TableServiceImplBase() {
-            @Override
-            public void range(StorageContainerRequest request,
-                              StreamObserver<StorageContainerResponse> responseObserver) {
-                receivedRequest.set(request);
-                receivedRequestType.set(KV_RANGE_REQ);
-                complete(responseObserver);
-            }
-
-            @Override
-            public void put(StorageContainerRequest request,
-                            StreamObserver<StorageContainerResponse> responseObserver) {
-                receivedRequest.set(request);
-                receivedRequestType.set(KV_PUT_REQ);
-                complete(responseObserver);
-            }
-
-            @Override
-            public void delete(StorageContainerRequest request,
-                               StreamObserver<StorageContainerResponse> responseObserver) {
-                receivedRequest.set(request);
-                receivedRequestType.set(KV_DELETE_REQ);
-                complete(responseObserver);
-            }
-
-            @Override
-            public void txn(StorageContainerRequest request,
-                            StreamObserver<StorageContainerResponse> responseObserver) {
-                receivedRequest.set(request);
-                receivedRequestType.set(KV_TXN_REQ);
-                complete(responseObserver);
-            }
-
-            @Override
-            public void increment(StorageContainerRequest request,
-                                  StreamObserver<StorageContainerResponse> responseObserver) {
-                receivedRequest.set(request);
-                receivedRequestType.set(KV_INCR_REQ);
-                complete(responseObserver);
-            }
-
-            private void complete(StreamObserver<StorageContainerResponse> responseStreamObserver) {
-                responseStreamObserver.onNext(response);
-                responseStreamObserver.onCompleted();
-            }
-        };
-        serviceRegistry.addService(tableService.bindService());
-        StorageServerChannel ssChannel = new StorageServerChannel(
-            InProcessChannelBuilder.forName(serverName).directExecutor().build(),
-            Optional.empty());
-        serverChannelFuture.complete(ssChannel);
-
-        StorageContainerRequest.Builder requestBuilder = StorageContainerRequest.newBuilder();
-        switch (type) {
-            case KV_PUT_REQ:
-                requestBuilder.setKvPutReq(PutRequest.newBuilder().build());
-                break;
-            case KV_DELETE_REQ:
-                requestBuilder.setKvDeleteReq(DeleteRangeRequest.newBuilder().build());
-                break;
-            case KV_RANGE_REQ:
-                requestBuilder.setKvRangeReq(RangeRequest.newBuilder().build());
-                break;
-            case KV_INCR_REQ:
-                requestBuilder.setKvIncrReq(IncrementRequest.newBuilder().build());
-                break;
-            case KV_TXN_REQ:
-                requestBuilder.setKvTxnReq(TxnRequest.newBuilder().build());
-                break;
-            default:
-                break;
-        }
-        StorageContainerRequest request = requestBuilder.build();
-
-        TableRequestProcessor<String> processor = TableRequestProcessor.of(
-            request,
-            resp -> "test",
-            scChannel,
-            scheduler,
-            ClientConstants.DEFAULT_INFINIT_BACKOFF_POLICY);
-        assertEquals("test", FutureUtils.result(processor.process()));
-        assertSame(request, receivedRequest.get());
-        assertEquals(type, receivedRequestType.get());
-    }
-
-}
diff --git a/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/TestKvUtils.java b/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/TestKvUtils.java
index 3cff0a6..d2df334 100644
--- a/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/TestKvUtils.java
+++ b/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/TestKvUtils.java
@@ -17,16 +17,8 @@ package org.apache.bookkeeper.clients.impl.kv;
 import static com.google.common.base.Charsets.UTF_8;
 import static org.apache.bookkeeper.clients.impl.kv.KvUtils.newDeleteRequest;
 import static org.apache.bookkeeper.clients.impl.kv.KvUtils.newIncrementRequest;
-import static org.apache.bookkeeper.clients.impl.kv.KvUtils.newKvDeleteRequest;
-import static org.apache.bookkeeper.clients.impl.kv.KvUtils.newKvIncrementRequest;
-import static org.apache.bookkeeper.clients.impl.kv.KvUtils.newKvPutRequest;
-import static org.apache.bookkeeper.clients.impl.kv.KvUtils.newKvRangeRequest;
 import static org.apache.bookkeeper.clients.impl.kv.KvUtils.newPutRequest;
 import static org.apache.bookkeeper.clients.impl.kv.KvUtils.newRangeRequest;
-import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_DELETE_REQ;
-import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_INCR_REQ;
-import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_PUT_REQ;
-import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_RANGE_REQ;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -45,7 +37,6 @@ import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeRequest;
 import org.apache.bookkeeper.stream.proto.kv.rpc.IncrementRequest;
 import org.apache.bookkeeper.stream.proto.kv.rpc.PutRequest;
 import org.apache.bookkeeper.stream.proto.kv.rpc.RangeRequest;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
 import org.junit.Test;
 
 /**
@@ -89,26 +80,6 @@ public class TestKvUtils {
     }
 
     @Test
-    public void testNewKvRangeRequest() {
-        try (RangeOption<ByteBuf> rangeOption = optionFactory.newRangeOption()
-            .endKey(key.retainedDuplicate())
-            .countOnly(true)
-            .keysOnly(true)
-            .limit(10)
-            .maxCreateRev(1234L)
-            .minCreateRev(234L)
-            .maxModRev(2345L)
-            .minModRev(1235L)
-            .build()) {
-            RangeRequest.Builder rrBuilder = newRangeRequest(key, rangeOption);
-            StorageContainerRequest request = newKvRangeRequest(scId, rrBuilder);
-            assertEquals(scId, request.getScId());
-            assertEquals(KV_RANGE_REQ, request.getRequestCase());
-            assertEquals(rrBuilder.build(), request.getKvRangeReq());
-        }
-    }
-
-    @Test
     public void testNewPutRequest() {
         try (PutOption<ByteBuf> option = Options.putAndGet()) {
             PutRequest rr = newPutRequest(key, value, option).build();
@@ -120,17 +91,6 @@ public class TestKvUtils {
     }
 
     @Test
-    public void testNewKvPutRequest() {
-        try (PutOption<ByteBuf> option = Options.putAndGet()) {
-            PutRequest.Builder putBuilder = newPutRequest(key, value, option);
-            StorageContainerRequest request = newKvPutRequest(scId, putBuilder);
-            assertEquals(scId, request.getScId());
-            assertEquals(KV_PUT_REQ, request.getRequestCase());
-            assertEquals(putBuilder.build(), request.getKvPutReq());
-        }
-    }
-
-    @Test
     public void testNewIncrementRequest() {
         try (IncrementOption<ByteBuf> option = Options.incrementAndGet()) {
             IncrementRequest rr = newIncrementRequest(key, 100L, option).build();
@@ -142,17 +102,6 @@ public class TestKvUtils {
     }
 
     @Test
-    public void testNewKvIncrementRequest() {
-        try (IncrementOption<ByteBuf> option = Options.incrementAndGet()) {
-            IncrementRequest.Builder incrBuilder = newIncrementRequest(key, 100L, option);
-            StorageContainerRequest request = newKvIncrementRequest(scId, incrBuilder);
-            assertEquals(scId, request.getScId());
-            assertEquals(KV_INCR_REQ, request.getRequestCase());
-            assertEquals(incrBuilder.build(), request.getKvIncrReq());
-        }
-    }
-
-    @Test
     public void testNewDeleteRequest() {
         try (DeleteOption<ByteBuf> option = optionFactory.newDeleteOption()
             .endKey(key.retainedDuplicate())
@@ -166,18 +115,4 @@ public class TestKvUtils {
         }
     }
 
-    @Test
-    public void testNewKvDeleteRequest() {
-        try (DeleteOption<ByteBuf> option = optionFactory.newDeleteOption()
-            .endKey(key.retainedDuplicate())
-            .prevKv(true)
-            .build()) {
-            DeleteRangeRequest.Builder delBuilder = newDeleteRequest(key, option);
-            StorageContainerRequest request = newKvDeleteRequest(scId, delBuilder);
-            assertEquals(scId, request.getScId());
-            assertEquals(KV_DELETE_REQ, request.getRequestCase());
-            assertEquals(delBuilder.build(), request.getKvDeleteReq());
-        }
-    }
-
 }
diff --git a/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/TxnRequestProcessorTest.java b/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/TxnRequestProcessorTest.java
new file mode 100644
index 0000000..2efecd0
--- /dev/null
+++ b/stream/clients/java/kv/src/test/java/org/apache/bookkeeper/clients/impl/kv/TxnRequestProcessorTest.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.bookkeeper.clients.impl.kv;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import io.grpc.inprocess.InProcessChannelBuilder;
+import io.grpc.stub.StreamObserver;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.atomic.AtomicReference;
+import lombok.Cleanup;
+import org.apache.bookkeeper.clients.grpc.GrpcClientTestBase;
+import org.apache.bookkeeper.clients.impl.channel.StorageServerChannel;
+import org.apache.bookkeeper.clients.impl.container.StorageContainerChannel;
+import org.apache.bookkeeper.clients.utils.ClientConstants;
+import org.apache.bookkeeper.common.concurrent.FutureUtils;
+import org.apache.bookkeeper.stream.proto.kv.rpc.ResponseHeader;
+import org.apache.bookkeeper.stream.proto.kv.rpc.TableServiceGrpc.TableServiceImplBase;
+import org.apache.bookkeeper.stream.proto.kv.rpc.TxnRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.TxnResponse;
+import org.apache.bookkeeper.stream.proto.storage.StatusCode;
+import org.junit.Test;
+
+/**
+ * Unit test of {@link TxnRequestProcessor}.
+ */
+public class TxnRequestProcessorTest extends GrpcClientTestBase {
+
+    @Override
+    protected void doSetup() throws Exception {
+    }
+
+    @Override
+    protected void doTeardown() throws Exception {
+    }
+
+    protected TxnResponse newSuccessResponse() {
+        return TxnResponse.newBuilder()
+            .setHeader(ResponseHeader.newBuilder()
+                .setCode(StatusCode.SUCCESS)
+                .build())
+            .build();
+    }
+
+    protected TxnRequest newRequest() {
+        return TxnRequest.newBuilder()
+            .build();
+    }
+
+    @Test
+    public void testProcess() throws Exception {
+        @Cleanup("shutdown") ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
+
+        StorageContainerChannel scChannel = mock(StorageContainerChannel.class);
+
+        CompletableFuture<StorageServerChannel> serverChannelFuture = FutureUtils.createFuture();
+        when(scChannel.getStorageContainerChannelFuture()).thenReturn(serverChannelFuture);
+
+        TxnResponse response = newSuccessResponse();
+
+        AtomicReference<Object> receivedRequest = new AtomicReference<>(null);
+        TableServiceImplBase tableService = new TableServiceImplBase() {
+
+            @Override
+            public void txn(TxnRequest request,
+                            StreamObserver<TxnResponse> responseObserver) {
+                receivedRequest.set(request);
+                complete(responseObserver);
+            }
+
+            private void complete(StreamObserver<TxnResponse> responseStreamObserver) {
+                responseStreamObserver.onNext(response);
+                responseStreamObserver.onCompleted();
+            }
+        };
+        serviceRegistry.addService(tableService.bindService());
+        StorageServerChannel ssChannel = new StorageServerChannel(
+            InProcessChannelBuilder.forName(serverName).directExecutor().build(),
+            Optional.empty());
+        serverChannelFuture.complete(ssChannel);
+
+        TxnRequest request = newRequest();
+
+        TxnRequestProcessor<String> processor = TxnRequestProcessor.of(
+            request,
+            resp -> "test",
+            scChannel,
+            scheduler,
+            ClientConstants.DEFAULT_INFINIT_BACKOFF_POLICY);
+        assertEquals("test", FutureUtils.result(processor.process()));
+        assertSame(request, receivedRequest.get());
+    }
+
+}
diff --git a/stream/proto/src/main/java/org/apache/bookkeeper/stream/protocol/util/ProtoUtils.java b/stream/proto/src/main/java/org/apache/bookkeeper/stream/protocol/util/ProtoUtils.java
index 35ed903..687388f 100644
--- a/stream/proto/src/main/java/org/apache/bookkeeper/stream/protocol/util/ProtoUtils.java
+++ b/stream/proto/src/main/java/org/apache/bookkeeper/stream/protocol/util/ProtoUtils.java
@@ -42,7 +42,6 @@ import org.apache.bookkeeper.stream.proto.storage.OneStorageContainerEndpointReq
 import org.apache.bookkeeper.stream.proto.storage.OneStorageContainerEndpointResponse;
 import org.apache.bookkeeper.stream.proto.storage.StatusCode;
 import org.apache.bookkeeper.stream.proto.storage.StorageContainerEndpoint;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
 
@@ -224,25 +223,17 @@ public class ProtoUtils {
     // Meta Range API
     //
 
-    private static StorageContainerRequest.Builder newScRequestBuilder(long scId) {
-        return StorageContainerRequest.newBuilder()
-            .setScId(scId);
-    }
-
-    public static StorageContainerRequest createGetActiveRangesRequest(long scId, long streamId) {
-        return newScRequestBuilder(scId)
-            .setGetActiveRangesReq(GetActiveRangesRequest.newBuilder()
-                .setStreamId(streamId))
-            .build();
+    public static GetActiveRangesRequest createGetActiveRangesRequest(long streamId) {
+        return GetActiveRangesRequest.newBuilder()
+                .setStreamId(streamId)
+                .build();
     }
 
-    public static StorageContainerRequest createGetActiveRangesRequest(long scId,
-                                                                       StreamProperties streamProps) {
-        return newScRequestBuilder(scId)
-            .setGetActiveRangesReq(GetActiveRangesRequest.newBuilder()
+    public static GetActiveRangesRequest createGetActiveRangesRequest(StreamProperties streamProps) {
+        return GetActiveRangesRequest.newBuilder()
                 .setStreamId(streamProps.getStreamId())
-                .setStreamProps(streamProps))
-            .build();
+                .setStreamProps(streamProps)
+                .build();
     }
 
     //
diff --git a/stream/proto/src/main/proto/kv_rpc.proto b/stream/proto/src/main/proto/kv_rpc.proto
index c324bcb..01e5cb6 100644
--- a/stream/proto/src/main/proto/kv_rpc.proto
+++ b/stream/proto/src/main/proto/kv_rpc.proto
@@ -18,6 +18,7 @@
 syntax = "proto3";
 
 import "kv.proto";
+import "storage.proto";
 
 package bookkeeper.proto.kv.rpc;
 
@@ -34,7 +35,7 @@ message RoutingHeader {
   bytes r_key           = 3;
 }
 
-service KV {
+service TableService {
   // Range gets the keys in the range from the key-value store.
   // NOT supported yet.
   rpc Range(RangeRequest) returns (RangeResponse) {}
@@ -47,7 +48,7 @@ service KV {
   // DeleteRange deletes the given range from the key-value store.
   // A delete request increments the revision of the key-value store
   // and generates a delete event in the event history for every deleted key.
-  rpc DeleteRange(DeleteRangeRequest) returns (DeleteRangeResponse) {}
+  rpc Delete(DeleteRangeRequest) returns (DeleteRangeResponse) {}
 
   // Txn processes multiple requests in a single transaction.
   // A txn request increments the revision of the key-value store
@@ -55,20 +56,17 @@ service KV {
   // It is not allowed to modify the same key several times within one txn.
   rpc Txn(TxnRequest) returns (TxnResponse) {}
 
+  // Increment increments the amount associated with the keys
+  rpc Increment(IncrementRequest) returns (IncrementResponse) {}
+
 }
 
 message ResponseHeader {
-  // cluster_id is the ID of the cluster which sent the response.
-  uint64 cluster_id = 1;
-  // member_id is the ID of the member which sent the response.
-  uint64 member_id = 2;
-  // revision is the key-value store revision when the request was applied.
-  int64 revision = 3;
-  // raft_term is the raft term when the request was applied.
-  uint64 raft_term = 4;
+  // Status Code
+  storage.StatusCode code               = 1;
 
   // routing header
-  RoutingHeader routing_header = 99;
+  RoutingHeader routing_header  = 99;
 }
 
 message RangeRequest {
diff --git a/stream/proto/src/main/proto/storage.proto b/stream/proto/src/main/proto/storage.proto
index b84ec2e..7570d29 100644
--- a/stream/proto/src/main/proto/storage.proto
+++ b/stream/proto/src/main/proto/storage.proto
@@ -19,7 +19,6 @@ syntax = "proto3";
 
 import "common.proto";
 import "stream.proto";
-import "kv_rpc.proto";
 
 package bookkeeper.proto.storage;
 
@@ -87,7 +86,8 @@ message GetActiveRangesRequest {
 }
 
 message GetActiveRangesResponse {
-    repeated RelatedRanges ranges       = 1;
+    StatusCode code                     = 1;
+    repeated RelatedRanges ranges       = 2;
 }
 
 enum RelationType {
@@ -104,7 +104,7 @@ message RelatedRanges {
 
 // public service for other operations in range server
 service MetaRangeService {
-    rpc GetActiveRanges(StorageContainerRequest)        returns (StorageContainerResponse);
+    rpc GetActiveRanges(GetActiveRangesRequest)        returns (GetActiveRangesResponse);
 }
 
 //
@@ -188,18 +188,6 @@ service RootRangeService {
 }
 
 //
-// KV Service
-//
-
-service TableService {
-    rpc Range(StorageContainerRequest) returns (StorageContainerResponse) {}
-    rpc Put(StorageContainerRequest) returns (StorageContainerResponse) {}
-    rpc Delete(StorageContainerRequest) returns (StorageContainerResponse) {}
-    rpc Increment(StorageContainerRequest) returns (StorageContainerResponse) {}
-    rpc Txn(StorageContainerRequest) returns (StorageContainerResponse) {}
-}
-
-//
 // StorageContainerService
 //
 
@@ -234,35 +222,3 @@ service StorageContainerService {
     // Get the storage container endpoints
     rpc GetStorageContainerEndpoint(GetStorageContainerEndpointRequest) returns (GetStorageContainerEndpointResponse);
 }
-
-message StorageContainerRequest {
-    int64 sc_id                 = 1;
-
-    oneof request {
-        // stream metadata operations
-        GetActiveRangesRequest get_active_ranges_req            = 200;
-
-        // kv operations
-        kv.rpc.RangeRequest kv_range_req                        = 400;
-        kv.rpc.PutRequest kv_put_req                            = 401;
-        kv.rpc.DeleteRangeRequest kv_delete_req                 = 402;
-        kv.rpc.TxnRequest kv_txn_req                            = 403;
-        kv.rpc.IncrementRequest kv_incr_req                     = 404;
-    }
-}
-
-message StorageContainerResponse {
-    StatusCode code             = 1;
-
-    oneof response {
-        // stream metadata operations
-        GetActiveRangesResponse get_active_ranges_resp          = 200;
-
-        // kv operations
-        kv.rpc.RangeResponse kv_range_resp                      = 400;
-        kv.rpc.PutResponse kv_put_resp                          = 401;
-        kv.rpc.DeleteRangeResponse kv_delete_resp               = 402;
-        kv.rpc.TxnResponse kv_txn_resp                          = 403;
-        kv.rpc.IncrementResponse kv_incr_resp                   = 404;
-    }
-}
diff --git a/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/kv/TableStore.java b/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/kv/TableStore.java
index 1eaac62..a584a37 100644
--- a/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/kv/TableStore.java
+++ b/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/kv/TableStore.java
@@ -18,22 +18,30 @@
 package org.apache.bookkeeper.stream.storage.api.kv;
 
 import java.util.concurrent.CompletableFuture;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
+import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeResponse;
+import org.apache.bookkeeper.stream.proto.kv.rpc.IncrementRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.IncrementResponse;
+import org.apache.bookkeeper.stream.proto.kv.rpc.PutRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.PutResponse;
+import org.apache.bookkeeper.stream.proto.kv.rpc.RangeRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.RangeResponse;
+import org.apache.bookkeeper.stream.proto.kv.rpc.TxnRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.TxnResponse;
 
 /**
  * The table store that stores and serves tables.
  */
 public interface TableStore {
 
-    CompletableFuture<StorageContainerResponse> range(StorageContainerRequest request);
+    CompletableFuture<RangeResponse> range(RangeRequest request);
 
-    CompletableFuture<StorageContainerResponse> put(StorageContainerRequest request);
+    CompletableFuture<PutResponse> put(PutRequest request);
 
-    CompletableFuture<StorageContainerResponse> delete(StorageContainerRequest request);
+    CompletableFuture<DeleteRangeResponse> delete(DeleteRangeRequest request);
 
-    CompletableFuture<StorageContainerResponse> txn(StorageContainerRequest request);
+    CompletableFuture<TxnResponse> txn(TxnRequest request);
 
-    CompletableFuture<StorageContainerResponse> incr(StorageContainerRequest request);
+    CompletableFuture<IncrementResponse> incr(IncrementRequest request);
 
 }
diff --git a/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/metadata/MetaRangeStore.java b/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/metadata/MetaRangeStore.java
index 4215dd5..7ef664d 100644
--- a/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/metadata/MetaRangeStore.java
+++ b/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/metadata/MetaRangeStore.java
@@ -19,8 +19,8 @@
 package org.apache.bookkeeper.stream.storage.api.metadata;
 
 import java.util.concurrent.CompletableFuture;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
+import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesRequest;
+import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesResponse;
 
 /**
  * The metadata store that store ranges.
@@ -33,6 +33,6 @@ public interface MetaRangeStore {
      * @param request the request
      * @return the active ranges
      */
-    CompletableFuture<StorageContainerResponse> getActiveRanges(StorageContainerRequest request);
+    CompletableFuture<GetActiveRangesResponse> getActiveRanges(GetActiveRangesRequest request);
 
 }
diff --git a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/grpc/GrpcMetaRangeService.java b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/grpc/GrpcMetaRangeService.java
index 2fe81e7..1fb0e44 100644
--- a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/grpc/GrpcMetaRangeService.java
+++ b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/grpc/GrpcMetaRangeService.java
@@ -19,12 +19,12 @@ package org.apache.bookkeeper.stream.storage.impl.grpc;
 
 import io.grpc.stub.StreamObserver;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesRequest;
+import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesResponse;
 import org.apache.bookkeeper.stream.proto.storage.MetaRangeServiceGrpc.MetaRangeServiceImplBase;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
-import org.apache.bookkeeper.stream.storage.impl.grpc.handler.StorageContainerResponseHandler;
-import org.apache.bookkeeper.stream.storage.api.RangeStore;
+import org.apache.bookkeeper.stream.proto.storage.StatusCode;
 import org.apache.bookkeeper.stream.storage.api.metadata.RangeStoreService;
+import org.apache.bookkeeper.stream.storage.impl.grpc.handler.ResponseHandler;
 
 /**
  * The gRPC protocol based range service.
@@ -44,10 +44,17 @@ public class GrpcMetaRangeService extends MetaRangeServiceImplBase {
     //
 
     @Override
-    public void getActiveRanges(StorageContainerRequest request,
-                                StreamObserver<StorageContainerResponse> responseObserver) {
+    public void getActiveRanges(GetActiveRangesRequest request,
+                                StreamObserver<GetActiveRangesResponse> responseObserver) {
         rangeStore.getActiveRanges(request).whenComplete(
-            StorageContainerResponseHandler.of(responseObserver));
+            new ResponseHandler<GetActiveRangesResponse>(responseObserver) {
+                @Override
+                protected GetActiveRangesResponse createErrorResp(Throwable cause) {
+                    return GetActiveRangesResponse.newBuilder()
+                        .setCode(StatusCode.INTERNAL_SERVER_ERROR)
+                        .build();
+                }
+            });
     }
 
 }
diff --git a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/grpc/GrpcTableService.java b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/grpc/GrpcTableService.java
index e86759d..f26a7bd 100644
--- a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/grpc/GrpcTableService.java
+++ b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/grpc/GrpcTableService.java
@@ -19,11 +19,21 @@ package org.apache.bookkeeper.stream.storage.impl.grpc;
 
 import io.grpc.stub.StreamObserver;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
-import org.apache.bookkeeper.stream.proto.storage.TableServiceGrpc.TableServiceImplBase;
-import org.apache.bookkeeper.stream.storage.impl.grpc.handler.StorageContainerResponseHandler;
+import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeResponse;
+import org.apache.bookkeeper.stream.proto.kv.rpc.IncrementRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.IncrementResponse;
+import org.apache.bookkeeper.stream.proto.kv.rpc.PutRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.PutResponse;
+import org.apache.bookkeeper.stream.proto.kv.rpc.RangeRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.RangeResponse;
+import org.apache.bookkeeper.stream.proto.kv.rpc.ResponseHeader;
+import org.apache.bookkeeper.stream.proto.kv.rpc.TableServiceGrpc.TableServiceImplBase;
+import org.apache.bookkeeper.stream.proto.kv.rpc.TxnRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.TxnResponse;
+import org.apache.bookkeeper.stream.proto.storage.StatusCode;
 import org.apache.bookkeeper.stream.storage.api.metadata.RangeStoreService;
+import org.apache.bookkeeper.stream.storage.impl.grpc.handler.ResponseHandler;
 
 /**
  * The gRPC protocol based k/v service.
@@ -39,35 +49,87 @@ public class GrpcTableService extends TableServiceImplBase {
     }
 
     @Override
-    public void range(StorageContainerRequest request,
-                      StreamObserver<StorageContainerResponse> responseObserver) {
+    public void range(RangeRequest request,
+                      StreamObserver<RangeResponse> responseObserver) {
         rangeStore.range(request).whenComplete(
-            StorageContainerResponseHandler.of(responseObserver));
+            new ResponseHandler<RangeResponse>(responseObserver) {
+                @Override
+                protected RangeResponse createErrorResp(Throwable cause) {
+                    return RangeResponse.newBuilder()
+                        .setHeader(ResponseHeader.newBuilder()
+                            .setCode(StatusCode.INTERNAL_SERVER_ERROR)
+                            .setRoutingHeader(request.getHeader())
+                            .build())
+                        .build();
+                }
+            });
     }
 
     @Override
-    public void put(StorageContainerRequest request,
-                    StreamObserver<StorageContainerResponse> responseObserver) {
+    public void put(PutRequest request,
+                    StreamObserver<PutResponse> responseObserver) {
         rangeStore.put(request).whenComplete(
-            StorageContainerResponseHandler.of(responseObserver));
+            new ResponseHandler<PutResponse>(responseObserver) {
+                @Override
+                protected PutResponse createErrorResp(Throwable cause) {
+                    return PutResponse.newBuilder()
+                        .setHeader(ResponseHeader.newBuilder()
+                            .setCode(StatusCode.INTERNAL_SERVER_ERROR)
+                            .setRoutingHeader(request.getHeader())
+                            .build())
+                        .build();
+                }
+            });
     }
 
     @Override
-    public void delete(StorageContainerRequest request,
-                       StreamObserver<StorageContainerResponse> responseObserver) {
+    public void delete(DeleteRangeRequest request,
+                       StreamObserver<DeleteRangeResponse> responseObserver) {
         rangeStore.delete(request).whenComplete(
-            StorageContainerResponseHandler.of(responseObserver));
+            new ResponseHandler<DeleteRangeResponse>(responseObserver) {
+                @Override
+                protected DeleteRangeResponse createErrorResp(Throwable cause) {
+                    return DeleteRangeResponse.newBuilder()
+                        .setHeader(ResponseHeader.newBuilder()
+                            .setCode(StatusCode.INTERNAL_SERVER_ERROR)
+                            .setRoutingHeader(request.getHeader())
+                            .build())
+                        .build();
+                }
+            });
     }
 
     @Override
-    public void txn(StorageContainerRequest request, StreamObserver<StorageContainerResponse> responseObserver) {
+    public void txn(TxnRequest request,
+                    StreamObserver<TxnResponse> responseObserver) {
         rangeStore.txn(request).whenComplete(
-            StorageContainerResponseHandler.of(responseObserver));
+            new ResponseHandler<TxnResponse>(responseObserver) {
+                @Override
+                protected TxnResponse createErrorResp(Throwable cause) {
+                    return TxnResponse.newBuilder()
+                        .setHeader(ResponseHeader.newBuilder()
+                            .setCode(StatusCode.INTERNAL_SERVER_ERROR)
+                            .setRoutingHeader(request.getHeader())
+                            .build())
+                        .build();
+                }
+            });
     }
 
     @Override
-    public void increment(StorageContainerRequest request, StreamObserver<StorageContainerResponse> responseObserver) {
+    public void increment(IncrementRequest request,
+                          StreamObserver<IncrementResponse> responseObserver) {
         rangeStore.incr(request).whenComplete(
-            StorageContainerResponseHandler.of(responseObserver));
+            new ResponseHandler<IncrementResponse>(responseObserver) {
+                @Override
+                protected IncrementResponse createErrorResp(Throwable cause) {
+                    return IncrementResponse.newBuilder()
+                        .setHeader(ResponseHeader.newBuilder()
+                            .setCode(StatusCode.INTERNAL_SERVER_ERROR)
+                            .setRoutingHeader(request.getHeader())
+                            .build())
+                        .build();
+                }
+            });
     }
 }
diff --git a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/grpc/handler/StorageContainerResponseHandler.java b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/grpc/handler/StorageContainerResponseHandler.java
deleted file mode 100644
index 42c21a4..0000000
--- a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/grpc/handler/StorageContainerResponseHandler.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.bookkeeper.stream.storage.impl.grpc.handler;
-
-import io.grpc.stub.StreamObserver;
-import org.apache.bookkeeper.stream.proto.storage.StatusCode;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
-
-/**
- * Response handler to handle storage container response.
- */
-public class StorageContainerResponseHandler extends ResponseHandler<StorageContainerResponse> {
-
-    public static StorageContainerResponseHandler of(StreamObserver<StorageContainerResponse> respObserver) {
-        return new StorageContainerResponseHandler(respObserver);
-    }
-
-    private StorageContainerResponseHandler(StreamObserver<StorageContainerResponse> respObserver) {
-        super(respObserver);
-    }
-
-    @Override
-    protected StorageContainerResponse createErrorResp(Throwable cause) {
-        return StorageContainerResponse.newBuilder()
-            .setCode(StatusCode.INTERNAL_SERVER_ERROR)
-            .build();
-    }
-}
diff --git a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/kv/TableStoreImpl.java b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/kv/TableStoreImpl.java
index d7ef678..9a9670a 100644
--- a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/kv/TableStoreImpl.java
+++ b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/kv/TableStoreImpl.java
@@ -19,7 +19,6 @@ package org.apache.bookkeeper.stream.storage.impl.kv;
 
 import static org.apache.bookkeeper.stream.storage.impl.kv.TableStoreUtils.fromProtoCompare;
 import static org.apache.bookkeeper.stream.storage.impl.kv.TableStoreUtils.handleCause;
-import static org.apache.bookkeeper.stream.storage.impl.kv.TableStoreUtils.mvccCodeToStatusCode;
 import static org.apache.bookkeeper.stream.storage.impl.kv.TableStoreUtils.newStoreKey;
 import static org.apache.bookkeeper.stream.storage.impl.kv.TableStoreUtils.processDeleteResult;
 import static org.apache.bookkeeper.stream.storage.impl.kv.TableStoreUtils.processIncrementResult;
@@ -46,17 +45,18 @@ import org.apache.bookkeeper.api.kv.result.TxnResult;
 import org.apache.bookkeeper.statelib.api.mvcc.MVCCAsyncStore;
 import org.apache.bookkeeper.stream.proto.kv.rpc.Compare;
 import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeResponse;
 import org.apache.bookkeeper.stream.proto.kv.rpc.IncrementRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.IncrementResponse;
 import org.apache.bookkeeper.stream.proto.kv.rpc.PutRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.PutResponse;
 import org.apache.bookkeeper.stream.proto.kv.rpc.RangeRequest;
 import org.apache.bookkeeper.stream.proto.kv.rpc.RangeResponse;
 import org.apache.bookkeeper.stream.proto.kv.rpc.RequestOp;
+import org.apache.bookkeeper.stream.proto.kv.rpc.ResponseHeader;
 import org.apache.bookkeeper.stream.proto.kv.rpc.RoutingHeader;
 import org.apache.bookkeeper.stream.proto.kv.rpc.TxnRequest;
 import org.apache.bookkeeper.stream.proto.kv.rpc.TxnResponse;
-import org.apache.bookkeeper.stream.proto.storage.StatusCode;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
 import org.apache.bookkeeper.stream.storage.api.kv.TableStore;
 
 /**
@@ -72,13 +72,11 @@ public class TableStoreImpl implements TableStore {
     }
 
     @Override
-    public CompletableFuture<StorageContainerResponse> range(StorageContainerRequest request) {
-        RangeRequest rangeReq = request.getKvRangeReq();
-
+    public CompletableFuture<RangeResponse> range(RangeRequest rangeReq) {
         if (log.isTraceEnabled()) {
             log.trace("Received range request {}", rangeReq);
         }
-        return range(rangeReq)
+        return doRange(rangeReq)
             .thenApply(result -> {
                 try {
                     RangeResponse rangeResp = processRangeResult(
@@ -89,19 +87,18 @@ public class TableStoreImpl implements TableStore {
                     result.close();
                 }
             })
-            .thenApply(rangeResp -> StorageContainerResponse.newBuilder()
-                .setCode(StatusCode.SUCCESS)
-                .setKvRangeResp(rangeResp)
-                .build())
             .exceptionally(cause -> {
                 log.error("Failed to process range request {}", rangeReq, cause);
-                return StorageContainerResponse.newBuilder()
-                    .setCode(handleCause(cause))
+                return RangeResponse.newBuilder()
+                    .setHeader(ResponseHeader.newBuilder()
+                        .setCode(handleCause(cause))
+                        .setRoutingHeader(rangeReq.getHeader())
+                        .build())
                     .build();
             });
     }
 
-    private CompletableFuture<RangeResult<byte[], byte[]>> range(RangeRequest request) {
+    private CompletableFuture<RangeResult<byte[], byte[]>> doRange(RangeRequest request) {
         RangeOp<byte[], byte[]> op = buildRangeOp(request.getHeader(), request);
         return store.range(op)
             .whenComplete((rangeResult, throwable) -> op.close());
@@ -143,10 +140,8 @@ public class TableStoreImpl implements TableStore {
     }
 
     @Override
-    public CompletableFuture<StorageContainerResponse> put(StorageContainerRequest request) {
-        PutRequest putReq = request.getKvPutReq();
-
-        return put(putReq)
+    public CompletableFuture<PutResponse> put(PutRequest putReq) {
+        return doPut(putReq)
             .thenApply(result -> {
                 try {
                     return processPutResult(
@@ -156,19 +151,18 @@ public class TableStoreImpl implements TableStore {
                     result.close();
                 }
             })
-            .thenApply(putResp -> StorageContainerResponse.newBuilder()
-                .setCode(StatusCode.SUCCESS)
-                .setKvPutResp(putResp)
-                .build())
             .exceptionally(cause -> {
                 log.error("Failed to process put request {}", putReq, cause);
-                return StorageContainerResponse.newBuilder()
-                    .setCode(handleCause(cause))
+                return PutResponse.newBuilder()
+                    .setHeader(ResponseHeader.newBuilder()
+                        .setCode(handleCause(cause))
+                        .setRoutingHeader(putReq.getHeader())
+                        .build())
                     .build();
             });
     }
 
-    private CompletableFuture<PutResult<byte[], byte[]>> put(PutRequest request) {
+    private CompletableFuture<PutResult<byte[], byte[]>> doPut(PutRequest request) {
         PutOp<byte[], byte[]> op = buildPutOp(request.getHeader(), request);
         return store.put(op)
             .whenComplete((putResult, throwable) -> op.close());
@@ -187,10 +181,8 @@ public class TableStoreImpl implements TableStore {
     }
 
     @Override
-    public CompletableFuture<StorageContainerResponse> incr(StorageContainerRequest request) {
-        IncrementRequest incrementReq = request.getKvIncrReq();
-
-        return increment(incrementReq)
+    public CompletableFuture<IncrementResponse> incr(IncrementRequest incrementReq) {
+        return doIncrement(incrementReq)
             .thenApply(result -> {
                 try {
                     return processIncrementResult(
@@ -200,19 +192,18 @@ public class TableStoreImpl implements TableStore {
                     result.close();
                 }
             })
-            .thenApply(incrementResp -> StorageContainerResponse.newBuilder()
-                .setCode(StatusCode.SUCCESS)
-                .setKvIncrResp(incrementResp)
-                .build())
             .exceptionally(cause -> {
                 log.error("Failed to process increment request {}", incrementReq, cause);
-                return StorageContainerResponse.newBuilder()
-                    .setCode(handleCause(cause))
+                return IncrementResponse.newBuilder()
+                    .setHeader(ResponseHeader.newBuilder()
+                        .setCode(handleCause(cause))
+                        .setRoutingHeader(incrementReq.getHeader())
+                        .build())
                     .build();
             });
     }
 
-    private CompletableFuture<IncrementResult<byte[], byte[]>> increment(IncrementRequest request) {
+    private CompletableFuture<IncrementResult<byte[], byte[]>> doIncrement(IncrementRequest request) {
         IncrementOp<byte[], byte[]> op = buildIncrementOp(request.getHeader(), request);
         return store.increment(op)
             .whenComplete((incrementResult, throwable) -> op.close());
@@ -231,10 +222,8 @@ public class TableStoreImpl implements TableStore {
     }
 
     @Override
-    public CompletableFuture<StorageContainerResponse> delete(StorageContainerRequest request) {
-        DeleteRangeRequest deleteReq = request.getKvDeleteReq();
-
-        return delete(deleteReq)
+    public CompletableFuture<DeleteRangeResponse> delete(DeleteRangeRequest deleteReq) {
+        return doDelete(deleteReq)
             .thenApply(result -> {
                 try {
                     return processDeleteResult(
@@ -244,16 +233,15 @@ public class TableStoreImpl implements TableStore {
                     result.close();
                 }
             })
-            .thenApply(deleteResp -> StorageContainerResponse.newBuilder()
-                .setCode(StatusCode.SUCCESS)
-                .setKvDeleteResp(deleteResp)
-                .build())
-            .exceptionally(cause -> StorageContainerResponse.newBuilder()
-                .setCode(handleCause(cause))
+            .exceptionally(cause -> DeleteRangeResponse.newBuilder()
+                .setHeader(ResponseHeader.newBuilder()
+                    .setCode(handleCause(cause))
+                    .setRoutingHeader(deleteReq.getHeader())
+                    .build())
                 .build());
     }
 
-    private CompletableFuture<DeleteResult<byte[], byte[]>> delete(DeleteRangeRequest request) {
+    private CompletableFuture<DeleteResult<byte[], byte[]>> doDelete(DeleteRangeRequest request) {
         DeleteOp<byte[], byte[]> op = buildDeleteOp(request.getHeader(), request);
         return store.delete(op)
             .whenComplete((deleteResult, throwable) -> op.close());
@@ -277,30 +265,27 @@ public class TableStoreImpl implements TableStore {
     }
 
     @Override
-    public CompletableFuture<StorageContainerResponse> txn(StorageContainerRequest request) {
-        TxnRequest txnReq = request.getKvTxnReq();
-
+    public CompletableFuture<TxnResponse> txn(TxnRequest txnReq) {
         if (log.isTraceEnabled()) {
             log.trace("Received txn request : {}", txnReq);
         }
-        return txn(txnReq)
+        return doTxn(txnReq)
             .thenApply(txnResult -> {
                 try {
-                    TxnResponse txnResponse = processTxnResult(txnReq.getHeader(), txnResult);
-                    return StorageContainerResponse.newBuilder()
-                        .setCode(mvccCodeToStatusCode(txnResult.code()))
-                        .setKvTxnResp(txnResponse)
-                        .build();
+                    return processTxnResult(txnReq.getHeader(), txnResult);
                 } finally {
                     txnResult.close();
                 }
             })
-            .exceptionally(cause -> StorageContainerResponse.newBuilder()
-                .setCode(handleCause(cause))
+            .exceptionally(cause -> TxnResponse.newBuilder()
+                .setHeader(ResponseHeader.newBuilder()
+                    .setCode(handleCause(cause))
+                    .setRoutingHeader(txnReq.getHeader())
+                    .build())
                 .build());
     }
 
-    private CompletableFuture<TxnResult<byte[], byte[]>> txn(TxnRequest request) {
+    private CompletableFuture<TxnResult<byte[], byte[]>> doTxn(TxnRequest request) {
         TxnOp<byte[], byte[]> op = buildTxnOp(request);
         return store.txn(op)
             .whenComplete((txnResult, throwable) -> op.close());
diff --git a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/kv/TableStoreUtils.java b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/kv/TableStoreUtils.java
index a9a8dce..964ca62 100644
--- a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/kv/TableStoreUtils.java
+++ b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/kv/TableStoreUtils.java
@@ -158,6 +158,7 @@ final class TableStoreUtils {
         ByteString rKey = routingHeader.getRKey();
         PutResponse.Builder putRespBuilder = PutResponse.newBuilder()
             .setHeader(ResponseHeader.newBuilder()
+                .setCode(mvccCodeToStatusCode(result.code()))
                 .setRoutingHeader(routingHeader)
                 .build());
         if (null != result.prevKv()) {
@@ -170,6 +171,7 @@ final class TableStoreUtils {
                                                     IncrementResult<byte[], byte[]> result) {
         IncrementResponse.Builder putRespBuilder = IncrementResponse.newBuilder()
             .setHeader(ResponseHeader.newBuilder()
+                .setCode(mvccCodeToStatusCode(result.code()))
                 .setRoutingHeader(routingHeader)
                 .build())
             .setTotalAmount(result.totalAmount());
@@ -182,6 +184,7 @@ final class TableStoreUtils {
         return RangeResponse.newBuilder()
             .setCount(result.count())
             .setHeader(ResponseHeader.newBuilder()
+                .setCode(mvccCodeToStatusCode(result.code()))
                 .setRoutingHeader(routingHeader)
                 .build())
             .addAllKvs(Lists.transform(result.kvs(), kv -> newKeyValue(rKey, kv)))
@@ -194,6 +197,7 @@ final class TableStoreUtils {
         ByteString rKey = routingHeader.getRKey();
         return DeleteRangeResponse.newBuilder()
             .setHeader(ResponseHeader.newBuilder()
+                .setCode(mvccCodeToStatusCode(result.code()))
                 .setRoutingHeader(routingHeader)
                 .build())
             .setDeleted(result.numDeleted())
@@ -205,6 +209,7 @@ final class TableStoreUtils {
                                         TxnResult<byte[], byte[]> txnResult) {
         return TxnResponse.newBuilder()
             .setHeader(ResponseHeader.newBuilder()
+                .setCode(mvccCodeToStatusCode(txnResult.code()))
                 .setRoutingHeader(routingHeader)
                 .build())
             .setSucceeded(txnResult.isSuccess())
diff --git a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/metadata/MetaRangeStoreImpl.java b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/metadata/MetaRangeStoreImpl.java
index 62502a2..530d4cd 100644
--- a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/metadata/MetaRangeStoreImpl.java
+++ b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/metadata/MetaRangeStoreImpl.java
@@ -18,9 +18,6 @@
 
 package org.apache.bookkeeper.stream.storage.impl.metadata;
 
-import static com.google.common.base.Preconditions.checkState;
-import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.GET_ACTIVE_RANGES_REQ;
-
 import com.google.common.collect.Maps;
 import java.util.Map;
 import java.util.concurrent.CompletableFuture;
@@ -30,12 +27,11 @@ import org.apache.bookkeeper.common.concurrent.FutureUtils;
 import org.apache.bookkeeper.statelib.api.mvcc.MVCCAsyncStore;
 import org.apache.bookkeeper.stream.proto.RangeMetadata;
 import org.apache.bookkeeper.stream.proto.StreamProperties;
+import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesRequest;
 import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesResponse;
 import org.apache.bookkeeper.stream.proto.storage.RelatedRanges;
 import org.apache.bookkeeper.stream.proto.storage.RelationType;
 import org.apache.bookkeeper.stream.proto.storage.StatusCode;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
 import org.apache.bookkeeper.stream.protocol.util.StorageContainerPlacementPolicy;
 import org.apache.bookkeeper.stream.storage.api.metadata.MetaRangeStore;
 import org.apache.bookkeeper.stream.storage.api.metadata.stream.MetaRange;
@@ -70,11 +66,11 @@ public class MetaRangeStoreImpl
     // Stream API
     //
 
-    private CompletableFuture<StorageContainerResponse> createStreamIfMissing(long streamId,
-                                                                              MetaRangeImpl metaRange,
-                                                                              StreamProperties streamProps) {
+    private CompletableFuture<GetActiveRangesResponse> createStreamIfMissing(long streamId,
+                                                                             MetaRangeImpl metaRange,
+                                                                             StreamProperties streamProps) {
         if (null == streamProps) {
-            return FutureUtils.value(StorageContainerResponse.newBuilder()
+            return FutureUtils.value(GetActiveRangesResponse.newBuilder()
                 .setCode(StatusCode.STREAM_NOT_FOUND)
                 .build());
         }
@@ -86,7 +82,7 @@ public class MetaRangeStoreImpl
                 }
                 return getActiveRanges(metaRange);
             } else {
-                return FutureUtils.value(StorageContainerResponse.newBuilder()
+                return FutureUtils.value(GetActiveRangesResponse.newBuilder()
                     .setCode(StatusCode.INTERNAL_SERVER_ERROR)
                     .build());
             }
@@ -94,11 +90,8 @@ public class MetaRangeStoreImpl
     }
 
     @Override
-    public CompletableFuture<StorageContainerResponse> getActiveRanges(StorageContainerRequest request) {
-        checkState(
-            GET_ACTIVE_RANGES_REQ == request.getRequestCase(),
-            "Wrong request type: %s", request.getRequestCase());
-        final long streamId = request.getGetActiveRangesReq().getStreamId();
+    public CompletableFuture<GetActiveRangesResponse> getActiveRanges(GetActiveRangesRequest request) {
+        final long streamId = request.getStreamId();
 
         MetaRangeImpl metaRange = streams.get(streamId);
 
@@ -107,8 +100,8 @@ public class MetaRangeStoreImpl
             return metaRangeImpl.load(streamId)
                 .thenCompose(mr -> {
                     if (null == mr) {
-                        StreamProperties streamProps = request.getGetActiveRangesReq().hasStreamProps()
-                            ? request.getGetActiveRangesReq().getStreamProps() : null;
+                        StreamProperties streamProps = request.hasStreamProps()
+                            ? request.getStreamProps() : null;
                         return createStreamIfMissing(streamId, metaRangeImpl, streamProps);
                     } else {
                         synchronized (streams) {
@@ -122,8 +115,7 @@ public class MetaRangeStoreImpl
         }
     }
 
-    private CompletableFuture<StorageContainerResponse> getActiveRanges(MetaRange metaRange) {
-        StorageContainerResponse.Builder scBuilder = StorageContainerResponse.newBuilder();
+    private CompletableFuture<GetActiveRangesResponse> getActiveRanges(MetaRange metaRange) {
         GetActiveRangesResponse.Builder respBuilder = GetActiveRangesResponse.newBuilder();
         return metaRange.getActiveRanges()
             .thenApplyAsync(ranges -> {
@@ -134,12 +126,11 @@ public class MetaRangeStoreImpl
                         .addAllRelatedRanges(range.getParentsList());
                     respBuilder.addRanges(rrBuilder);
                 }
-                return scBuilder
+                return respBuilder
                     .setCode(StatusCode.SUCCESS)
-                    .setGetActiveRangesResp(respBuilder)
                     .build();
             }, executor)
-            .exceptionally(cause -> scBuilder.setCode(StatusCode.INTERNAL_SERVER_ERROR).build());
+            .exceptionally(cause -> respBuilder.setCode(StatusCode.INTERNAL_SERVER_ERROR).build());
     }
 
 }
diff --git a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/FailRequestRangeStoreService.java b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/FailRequestRangeStoreService.java
index e15b808..4a1be55 100644
--- a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/FailRequestRangeStoreService.java
+++ b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/FailRequestRangeStoreService.java
@@ -18,13 +18,21 @@
 
 package org.apache.bookkeeper.stream.storage.impl.service;
 
-import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.ROOT_STORAGE_CONTAINER_ID;
-
 import io.grpc.Status;
 import io.grpc.StatusRuntimeException;
 import java.util.concurrent.CompletableFuture;
 import org.apache.bookkeeper.common.concurrent.FutureUtils;
 import org.apache.bookkeeper.common.util.OrderedScheduler;
+import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeResponse;
+import org.apache.bookkeeper.stream.proto.kv.rpc.IncrementRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.IncrementResponse;
+import org.apache.bookkeeper.stream.proto.kv.rpc.PutRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.PutResponse;
+import org.apache.bookkeeper.stream.proto.kv.rpc.RangeRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.RangeResponse;
+import org.apache.bookkeeper.stream.proto.kv.rpc.TxnRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.TxnResponse;
 import org.apache.bookkeeper.stream.proto.storage.CreateNamespaceRequest;
 import org.apache.bookkeeper.stream.proto.storage.CreateNamespaceResponse;
 import org.apache.bookkeeper.stream.proto.storage.CreateStreamRequest;
@@ -33,12 +41,12 @@ import org.apache.bookkeeper.stream.proto.storage.DeleteNamespaceRequest;
 import org.apache.bookkeeper.stream.proto.storage.DeleteNamespaceResponse;
 import org.apache.bookkeeper.stream.proto.storage.DeleteStreamRequest;
 import org.apache.bookkeeper.stream.proto.storage.DeleteStreamResponse;
+import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesRequest;
+import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesResponse;
 import org.apache.bookkeeper.stream.proto.storage.GetNamespaceRequest;
 import org.apache.bookkeeper.stream.proto.storage.GetNamespaceResponse;
 import org.apache.bookkeeper.stream.proto.storage.GetStreamRequest;
 import org.apache.bookkeeper.stream.proto.storage.GetStreamResponse;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
 import org.apache.bookkeeper.stream.storage.api.metadata.RangeStoreService;
 
 /**
@@ -56,11 +64,10 @@ final class FailRequestRangeStoreService implements RangeStoreService {
         this.scheduler = scheduler;
     }
 
-    private <T> CompletableFuture<T> failWrongGroupRequest(long scId) {
+    private <T> CompletableFuture<T> failWrongGroupRequest() {
         CompletableFuture<T> future = FutureUtils.createFuture();
-        scheduler.executeOrdered(scId, () -> {
-            future.completeExceptionally(new StatusRuntimeException(Status.NOT_FOUND));
-        });
+        scheduler.execute(() ->
+            future.completeExceptionally(new StatusRuntimeException(Status.NOT_FOUND)));
         return future;
     }
 
@@ -80,17 +87,17 @@ final class FailRequestRangeStoreService implements RangeStoreService {
 
     @Override
     public CompletableFuture<CreateNamespaceResponse> createNamespace(CreateNamespaceRequest request) {
-        return failWrongGroupRequest(ROOT_STORAGE_CONTAINER_ID);
+        return failWrongGroupRequest();
     }
 
     @Override
     public CompletableFuture<DeleteNamespaceResponse> deleteNamespace(DeleteNamespaceRequest request) {
-        return failWrongGroupRequest(ROOT_STORAGE_CONTAINER_ID);
+        return failWrongGroupRequest();
     }
 
     @Override
     public CompletableFuture<GetNamespaceResponse> getNamespace(GetNamespaceRequest request) {
-        return failWrongGroupRequest(ROOT_STORAGE_CONTAINER_ID);
+        return failWrongGroupRequest();
     }
 
     //
@@ -99,17 +106,17 @@ final class FailRequestRangeStoreService implements RangeStoreService {
 
     @Override
     public CompletableFuture<CreateStreamResponse> createStream(CreateStreamRequest request) {
-        return failWrongGroupRequest(ROOT_STORAGE_CONTAINER_ID);
+        return failWrongGroupRequest();
     }
 
     @Override
     public CompletableFuture<DeleteStreamResponse> deleteStream(DeleteStreamRequest request) {
-        return failWrongGroupRequest(ROOT_STORAGE_CONTAINER_ID);
+        return failWrongGroupRequest();
     }
 
     @Override
     public CompletableFuture<GetStreamResponse> getStream(GetStreamRequest request) {
-        return failWrongGroupRequest(ROOT_STORAGE_CONTAINER_ID);
+        return failWrongGroupRequest();
     }
 
     //
@@ -117,8 +124,8 @@ final class FailRequestRangeStoreService implements RangeStoreService {
     //
 
     @Override
-    public CompletableFuture<StorageContainerResponse> getActiveRanges(StorageContainerRequest request) {
-        return failWrongGroupRequest(request.getScId());
+    public CompletableFuture<GetActiveRangesResponse> getActiveRanges(GetActiveRangesRequest request) {
+        return failWrongGroupRequest();
     }
 
     //
@@ -127,27 +134,27 @@ final class FailRequestRangeStoreService implements RangeStoreService {
 
 
     @Override
-    public CompletableFuture<StorageContainerResponse> range(StorageContainerRequest request) {
-        return failWrongGroupRequest(request.getScId());
+    public CompletableFuture<RangeResponse> range(RangeRequest request) {
+        return failWrongGroupRequest();
     }
 
     @Override
-    public CompletableFuture<StorageContainerResponse> put(StorageContainerRequest request) {
-        return failWrongGroupRequest(request.getScId());
+    public CompletableFuture<PutResponse> put(PutRequest request) {
+        return failWrongGroupRequest();
     }
 
     @Override
-    public CompletableFuture<StorageContainerResponse> delete(StorageContainerRequest request) {
-        return failWrongGroupRequest(request.getScId());
+    public CompletableFuture<DeleteRangeResponse> delete(DeleteRangeRequest request) {
+        return failWrongGroupRequest();
     }
 
     @Override
-    public CompletableFuture<StorageContainerResponse> txn(StorageContainerRequest request) {
-        return failWrongGroupRequest(request.getScId());
+    public CompletableFuture<TxnResponse> txn(TxnRequest request) {
+        return failWrongGroupRequest();
     }
 
     @Override
-    public CompletableFuture<StorageContainerResponse> incr(StorageContainerRequest request) {
-        return failWrongGroupRequest(request.getScId());
+    public CompletableFuture<IncrementResponse> incr(IncrementRequest request) {
+        return failWrongGroupRequest();
     }
 }
diff --git a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreServiceImpl.java b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreServiceImpl.java
index 0304fc8..7adcefd 100644
--- a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreServiceImpl.java
+++ b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreServiceImpl.java
@@ -18,12 +18,6 @@
 
 package org.apache.bookkeeper.stream.storage.impl.service;
 
-import static com.google.common.base.Preconditions.checkArgument;
-import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_DELETE_REQ;
-import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_INCR_REQ;
-import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_PUT_REQ;
-import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_RANGE_REQ;
-import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_TXN_REQ;
 import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.CONTAINER_META_RANGE_ID;
 import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.CONTAINER_META_STREAM_ID;
 import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.ROOT_RANGE_ID;
@@ -40,11 +34,16 @@ import lombok.extern.slf4j.Slf4j;
 import org.apache.bookkeeper.common.concurrent.FutureUtils;
 import org.apache.bookkeeper.common.util.OrderedScheduler;
 import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeResponse;
 import org.apache.bookkeeper.stream.proto.kv.rpc.IncrementRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.IncrementResponse;
 import org.apache.bookkeeper.stream.proto.kv.rpc.PutRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.PutResponse;
 import org.apache.bookkeeper.stream.proto.kv.rpc.RangeRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.RangeResponse;
 import org.apache.bookkeeper.stream.proto.kv.rpc.RoutingHeader;
 import org.apache.bookkeeper.stream.proto.kv.rpc.TxnRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.TxnResponse;
 import org.apache.bookkeeper.stream.proto.storage.CreateNamespaceRequest;
 import org.apache.bookkeeper.stream.proto.storage.CreateNamespaceResponse;
 import org.apache.bookkeeper.stream.proto.storage.CreateStreamRequest;
@@ -53,12 +52,12 @@ import org.apache.bookkeeper.stream.proto.storage.DeleteNamespaceRequest;
 import org.apache.bookkeeper.stream.proto.storage.DeleteNamespaceResponse;
 import org.apache.bookkeeper.stream.proto.storage.DeleteStreamRequest;
 import org.apache.bookkeeper.stream.proto.storage.DeleteStreamResponse;
+import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesRequest;
+import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesResponse;
 import org.apache.bookkeeper.stream.proto.storage.GetNamespaceRequest;
 import org.apache.bookkeeper.stream.proto.storage.GetNamespaceResponse;
 import org.apache.bookkeeper.stream.proto.storage.GetStreamRequest;
 import org.apache.bookkeeper.stream.proto.storage.GetStreamResponse;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
 import org.apache.bookkeeper.stream.protocol.RangeId;
 import org.apache.bookkeeper.stream.protocol.util.StorageContainerPlacementPolicy;
 import org.apache.bookkeeper.stream.storage.api.kv.TableStore;
@@ -232,7 +231,7 @@ class RangeStoreServiceImpl implements RangeStoreService, AutoCloseable {
     //
 
     @Override
-    public CompletableFuture<StorageContainerResponse> getActiveRanges(StorageContainerRequest request) {
+    public CompletableFuture<GetActiveRangesResponse> getActiveRanges(GetActiveRangesRequest request) {
         return mgStore.getActiveRanges(request);
     }
 
@@ -242,12 +241,8 @@ class RangeStoreServiceImpl implements RangeStoreService, AutoCloseable {
 
 
     @Override
-    public CompletableFuture<StorageContainerResponse> range(StorageContainerRequest request) {
-        checkArgument(KV_RANGE_REQ == request.getRequestCase());
-
-        long scId = request.getScId();
-        RangeRequest rr = request.getKvRangeReq();
-        RoutingHeader header = rr.getHeader();
+    public CompletableFuture<RangeResponse> range(RangeRequest request) {
+        RoutingHeader header = request.getHeader();
 
         RangeId rid = RangeId.of(header.getStreamId(), header.getRangeId());
         TableStore store = tableStoreCache.getTableStore(rid);
@@ -260,12 +255,8 @@ class RangeStoreServiceImpl implements RangeStoreService, AutoCloseable {
     }
 
     @Override
-    public CompletableFuture<StorageContainerResponse> put(StorageContainerRequest request) {
-        checkArgument(KV_PUT_REQ == request.getRequestCase());
-
-        long scId = request.getScId();
-        PutRequest rr = request.getKvPutReq();
-        RoutingHeader header = rr.getHeader();
+    public CompletableFuture<PutResponse> put(PutRequest request) {
+        RoutingHeader header = request.getHeader();
 
         RangeId rid = RangeId.of(header.getStreamId(), header.getRangeId());
         TableStore store = tableStoreCache.getTableStore(rid);
@@ -278,12 +269,8 @@ class RangeStoreServiceImpl implements RangeStoreService, AutoCloseable {
     }
 
     @Override
-    public CompletableFuture<StorageContainerResponse> delete(StorageContainerRequest request) {
-        checkArgument(KV_DELETE_REQ == request.getRequestCase());
-
-        long scId = request.getScId();
-        DeleteRangeRequest rr = request.getKvDeleteReq();
-        RoutingHeader header = rr.getHeader();
+    public CompletableFuture<DeleteRangeResponse> delete(DeleteRangeRequest request) {
+        RoutingHeader header = request.getHeader();
 
         RangeId rid = RangeId.of(header.getStreamId(), header.getRangeId());
         TableStore store = tableStoreCache.getTableStore(rid);
@@ -296,12 +283,8 @@ class RangeStoreServiceImpl implements RangeStoreService, AutoCloseable {
     }
 
     @Override
-    public CompletableFuture<StorageContainerResponse> txn(StorageContainerRequest request) {
-        checkArgument(KV_TXN_REQ == request.getRequestCase());
-
-        long scId = request.getScId();
-        TxnRequest rr = request.getKvTxnReq();
-        RoutingHeader header = rr.getHeader();
+    public CompletableFuture<TxnResponse> txn(TxnRequest request) {
+        RoutingHeader header = request.getHeader();
 
         RangeId rid = RangeId.of(header.getStreamId(), header.getRangeId());
         TableStore store = tableStoreCache.getTableStore(rid);
@@ -314,12 +297,8 @@ class RangeStoreServiceImpl implements RangeStoreService, AutoCloseable {
     }
 
     @Override
-    public CompletableFuture<StorageContainerResponse> incr(StorageContainerRequest request) {
-        checkArgument(KV_INCR_REQ == request.getRequestCase());
-
-        long scId = request.getScId();
-        IncrementRequest ir = request.getKvIncrReq();
-        RoutingHeader header = ir.getHeader();
+    public CompletableFuture<IncrementResponse> incr(IncrementRequest request) {
+        RoutingHeader header = request.getHeader();
 
         RangeId rid = RangeId.of(header.getStreamId(), header.getRangeId());
         TableStore store = tableStoreCache.getTableStore(rid);
diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/TestStorageContainerStoreImpl.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/TestStorageContainerStoreImpl.java
index a269466..9293117 100644
--- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/TestStorageContainerStoreImpl.java
+++ b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/TestStorageContainerStoreImpl.java
@@ -16,7 +16,6 @@ package org.apache.bookkeeper.stream.storage.impl;
 
 import static org.apache.bookkeeper.common.util.ListenableFutures.fromListenableFuture;
 import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.DEFAULT_STREAM_CONF;
-import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.ROOT_STORAGE_CONTAINER_ID;
 import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createCreateNamespaceRequest;
 import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createCreateStreamRequest;
 import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createDeleteNamespaceRequest;
@@ -46,6 +45,7 @@ import io.grpc.inprocess.InProcessServerBuilder;
 import java.util.Collection;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ThreadLocalRandom;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.bookkeeper.clients.impl.container.StorageContainerClientInterceptor;
 import org.apache.bookkeeper.common.concurrent.FutureUtils;
@@ -64,6 +64,8 @@ import org.apache.bookkeeper.stream.proto.kv.rpc.RangeRequest;
 import org.apache.bookkeeper.stream.proto.kv.rpc.RangeResponse;
 import org.apache.bookkeeper.stream.proto.kv.rpc.ResponseHeader;
 import org.apache.bookkeeper.stream.proto.kv.rpc.RoutingHeader;
+import org.apache.bookkeeper.stream.proto.kv.rpc.TableServiceGrpc;
+import org.apache.bookkeeper.stream.proto.kv.rpc.TableServiceGrpc.TableServiceFutureStub;
 import org.apache.bookkeeper.stream.proto.storage.CreateNamespaceRequest;
 import org.apache.bookkeeper.stream.proto.storage.CreateNamespaceResponse;
 import org.apache.bookkeeper.stream.proto.storage.CreateStreamRequest;
@@ -72,6 +74,8 @@ import org.apache.bookkeeper.stream.proto.storage.DeleteNamespaceRequest;
 import org.apache.bookkeeper.stream.proto.storage.DeleteNamespaceResponse;
 import org.apache.bookkeeper.stream.proto.storage.DeleteStreamRequest;
 import org.apache.bookkeeper.stream.proto.storage.DeleteStreamResponse;
+import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesRequest;
+import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesResponse;
 import org.apache.bookkeeper.stream.proto.storage.GetNamespaceRequest;
 import org.apache.bookkeeper.stream.proto.storage.GetNamespaceResponse;
 import org.apache.bookkeeper.stream.proto.storage.GetStreamRequest;
@@ -81,10 +85,6 @@ import org.apache.bookkeeper.stream.proto.storage.MetaRangeServiceGrpc.MetaRange
 import org.apache.bookkeeper.stream.proto.storage.RootRangeServiceGrpc;
 import org.apache.bookkeeper.stream.proto.storage.RootRangeServiceGrpc.RootRangeServiceFutureStub;
 import org.apache.bookkeeper.stream.proto.storage.StatusCode;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
-import org.apache.bookkeeper.stream.proto.storage.TableServiceGrpc;
-import org.apache.bookkeeper.stream.proto.storage.TableServiceGrpc.TableServiceFutureStub;
 import org.apache.bookkeeper.stream.storage.api.metadata.RangeStoreService;
 import org.apache.bookkeeper.stream.storage.api.service.RangeStoreServiceFactory;
 import org.apache.bookkeeper.stream.storage.conf.StorageConfiguration;
@@ -140,6 +140,7 @@ public class TestStorageContainerStoreImpl {
     private TableServiceFutureStub tableService;
     private RootRangeServiceFutureStub rootRangeService;
     private MetaRangeServiceFutureStub metaRangeService;
+    private long scId;
 
     //
     // Utils for table api
@@ -156,64 +157,52 @@ public class TestStorageContainerStoreImpl {
         .setRoutingHeader(TEST_ROUTING_HEADER)
         .build();
 
-    private static StorageContainerRequest createPutRequest(long scId) {
-        return StorageContainerRequest.newBuilder()
-            .setScId(scId)
-            .setKvPutReq(PutRequest.newBuilder()
+    private static PutRequest createPutRequest() {
+        return PutRequest.newBuilder()
                 .setHeader(TEST_ROUTING_HEADER)
                 .setKey(TEST_KEY)
                 .setValue(TEST_VAL)
-                .build())
-            .build();
+                .build();
     }
 
-    private static StorageContainerResponse createPutResponse(StatusCode code) {
-        return StorageContainerResponse.newBuilder()
-            .setCode(code)
-            .setKvPutResp(PutResponse.newBuilder()
-                .setHeader(TEST_RESP_HEADER)
-                .build())
-            .build();
+    private static PutResponse createPutResponse(StatusCode code) {
+        return PutResponse.newBuilder()
+                .setHeader(ResponseHeader.newBuilder(TEST_RESP_HEADER)
+                    .setCode(code)
+                    .build())
+                .build();
     }
 
-    private static StorageContainerRequest createRangeRequest(long scId) {
-        return StorageContainerRequest.newBuilder()
-            .setScId(scId)
-            .setKvRangeReq(RangeRequest.newBuilder()
+    private static RangeRequest createRangeRequest() {
+        return RangeRequest.newBuilder()
                 .setHeader(TEST_ROUTING_HEADER)
                 .setKey(TEST_KEY)
-                .build())
-            .build();
+                .build();
     }
 
-    private static StorageContainerResponse createRangeResponse(StatusCode code) {
-        return StorageContainerResponse.newBuilder()
-            .setCode(code)
-            .setKvRangeResp(RangeResponse.newBuilder()
-                .setHeader(TEST_RESP_HEADER)
+    private static RangeResponse createRangeResponse(StatusCode code) {
+        return RangeResponse.newBuilder()
+                .setHeader(ResponseHeader.newBuilder(TEST_RESP_HEADER)
+                    .setCode(code)
+                    .build())
                 .setCount(0)
-                .build())
-            .build();
+                .build();
     }
 
-    private static StorageContainerRequest createDeleteRequest(long scId) {
-        return StorageContainerRequest.newBuilder()
-            .setScId(scId)
-            .setKvDeleteReq(DeleteRangeRequest.newBuilder()
+    private static DeleteRangeRequest createDeleteRequest() {
+        return DeleteRangeRequest.newBuilder()
                 .setHeader(TEST_ROUTING_HEADER)
                 .setKey(TEST_KEY)
-                .build())
-            .build();
+                .build();
     }
 
-    private static StorageContainerResponse createDeleteResponse(StatusCode code) {
-        return StorageContainerResponse.newBuilder()
-            .setCode(code)
-            .setKvDeleteResp(DeleteRangeResponse.newBuilder()
-                .setHeader(TEST_RESP_HEADER)
+    private static DeleteRangeResponse createDeleteResponse(StatusCode code) {
+        return DeleteRangeResponse.newBuilder()
+                .setHeader(ResponseHeader.newBuilder(TEST_RESP_HEADER)
+                    .setCode(code)
+                    .build())
                 .setDeleted(0)
-                .build())
-            .build();
+                .build();
     }
 
     @SuppressWarnings("unchecked")
@@ -263,10 +252,12 @@ public class TestStorageContainerStoreImpl {
             .usePlaintext()
             .build();
 
+        scId = ThreadLocalRandom.current().nextInt(2);
+
         // intercept the channel with storage container information.
         channel = ClientInterceptors.intercept(
             channel,
-            new StorageContainerClientInterceptor(0L));
+            new StorageContainerClientInterceptor(scId));
 
 
         tableService = TableServiceGrpc.newFutureStub(channel);
@@ -307,7 +298,7 @@ public class TestStorageContainerStoreImpl {
 
     @Test
     public void testCreateNamespaceNoRootStorageContainerStore() throws Exception {
-        rangeStore.getRegistry().stopStorageContainer(ROOT_STORAGE_CONTAINER_ID).join();
+        rangeStore.getRegistry().stopStorageContainer(scId).join();
 
         String colName = "test-create-namespace-no-root-storage-container-store";
         verifyNotFoundException(fromListenableFuture(
@@ -317,7 +308,7 @@ public class TestStorageContainerStoreImpl {
 
     @Test
     public void testDeleteNamespaceNoRootStorageContainerStore() throws Exception {
-        rangeStore.getRegistry().stopStorageContainer(ROOT_STORAGE_CONTAINER_ID).join();
+        rangeStore.getRegistry().stopStorageContainer(scId).join();
 
         String colName = "test-delete-namespace-no-root-storage-container-store";
         verifyNotFoundException(fromListenableFuture(
@@ -327,7 +318,7 @@ public class TestStorageContainerStoreImpl {
 
     @Test
     public void testGetNamespaceNoRootStorageContainerStore() throws Exception {
-        rangeStore.getRegistry().stopStorageContainer(ROOT_STORAGE_CONTAINER_ID).join();
+        rangeStore.getRegistry().stopStorageContainer(scId).join();
 
         String colName = "test-get-namespace-no-root-storage-container-store";
         verifyNotFoundException(fromListenableFuture(
@@ -395,7 +386,7 @@ public class TestStorageContainerStoreImpl {
 
     @Test
     public void testCreateStreamNoRootStorageContainerStore() throws Exception {
-        rangeStore.getRegistry().stopStorageContainer(ROOT_STORAGE_CONTAINER_ID).join();
+        rangeStore.getRegistry().stopStorageContainer(scId).join();
 
         String colName = "test-create-namespace-no-root-storage-container-store";
         String streamName = colName;
@@ -406,7 +397,7 @@ public class TestStorageContainerStoreImpl {
 
     @Test
     public void testDeleteStreamNoRootStorageContainerStore() throws Exception {
-        rangeStore.getRegistry().stopStorageContainer(ROOT_STORAGE_CONTAINER_ID).join();
+        rangeStore.getRegistry().stopStorageContainer(scId).join();
 
         String colName = "test-delete-namespace-no-root-storage-container-store";
         String streamName = colName;
@@ -417,7 +408,7 @@ public class TestStorageContainerStoreImpl {
 
     @Test
     public void testGetStreamNoRootStorageContainerStore() throws Exception {
-        rangeStore.getRegistry().stopStorageContainer(ROOT_STORAGE_CONTAINER_ID).join();
+        rangeStore.getRegistry().stopStorageContainer(scId).join();
 
         String colName = "test-get-namespace-no-root-storage-container-store";
         String streamName = colName;
@@ -482,26 +473,24 @@ public class TestStorageContainerStoreImpl {
 
     @Test
     public void testGetActiveRangesNoManager() throws Exception {
-        rangeStore.getRegistry().stopStorageContainer(ROOT_STORAGE_CONTAINER_ID).join();
+        rangeStore.getRegistry().stopStorageContainer(scId).join();
 
         verifyNotFoundException(fromListenableFuture(
-            metaRangeService.getActiveRanges(createGetActiveRangesRequest(12L, 34L))),
+            metaRangeService.getActiveRanges(createGetActiveRangesRequest(34L))),
             Status.NOT_FOUND);
     }
 
     @Test
     public void testGetActiveRangesMockManager() throws Exception {
-        long scId = System.currentTimeMillis();
-
-        StorageContainerResponse resp = StorageContainerResponse.newBuilder()
+        GetActiveRangesResponse resp = GetActiveRangesResponse.newBuilder()
             .setCode(StatusCode.STREAM_NOT_FOUND)
             .build();
-        StorageContainerRequest request = createGetActiveRangesRequest(scId, 34L);
+        GetActiveRangesRequest request = createGetActiveRangesRequest(34L);
 
         when(mockRangeStoreService.getActiveRanges(request))
             .thenReturn(CompletableFuture.completedFuture(resp));
 
-        CompletableFuture<StorageContainerResponse> future = fromListenableFuture(
+        CompletableFuture<GetActiveRangesResponse> future = fromListenableFuture(
             metaRangeService.getActiveRanges(request));
         verify(mockRangeStoreService, times(1)).getActiveRanges(request);
         assertTrue(resp == future.get());
@@ -514,40 +503,40 @@ public class TestStorageContainerStoreImpl {
 
     @Test
     public void testPutNoStorageContainer() throws Exception {
-        rangeStore.getRegistry().stopStorageContainer(ROOT_STORAGE_CONTAINER_ID).join();
+        rangeStore.getRegistry().stopStorageContainer(scId).join();
 
         verifyNotFoundException(fromListenableFuture(
-            tableService.put(createPutRequest(ROOT_STORAGE_CONTAINER_ID))),
+            tableService.put(createPutRequest())),
             Status.NOT_FOUND);
     }
 
     @Test
     public void testDeleteNoStorageContainer() throws Exception {
-        rangeStore.getRegistry().stopStorageContainer(ROOT_STORAGE_CONTAINER_ID).join();
+        rangeStore.getRegistry().stopStorageContainer(scId).join();
 
         verifyNotFoundException(fromListenableFuture(
-            tableService.delete(createDeleteRequest(ROOT_STORAGE_CONTAINER_ID))),
+            tableService.delete(createDeleteRequest())),
             Status.NOT_FOUND);
     }
 
     @Test
     public void testRangeNoStorageContainer() throws Exception {
-        rangeStore.getRegistry().stopStorageContainer(ROOT_STORAGE_CONTAINER_ID).join();
+        rangeStore.getRegistry().stopStorageContainer(scId).join();
 
         verifyNotFoundException(fromListenableFuture(
-            tableService.range(createRangeRequest(ROOT_STORAGE_CONTAINER_ID))),
+            tableService.range(createRangeRequest())),
             Status.NOT_FOUND);
     }
 
     @Test
     public void testRangeMockStorageContainer() throws Exception {
-        StorageContainerResponse response = createRangeResponse(StatusCode.SUCCESS);
-        StorageContainerRequest request = createRangeRequest(ROOT_STORAGE_CONTAINER_ID);
+        RangeResponse response = createRangeResponse(StatusCode.SUCCESS);
+        RangeRequest request = createRangeRequest();
 
         when(mockRangeStoreService.range(request))
             .thenReturn(CompletableFuture.completedFuture(response));
 
-        CompletableFuture<StorageContainerResponse> future = fromListenableFuture(
+        CompletableFuture<RangeResponse> future = fromListenableFuture(
             tableService.range(request));
         verify(mockRangeStoreService, times(1)).range(eq(request));
         assertTrue(response == future.get());
@@ -555,13 +544,13 @@ public class TestStorageContainerStoreImpl {
 
     @Test
     public void testDeleteMockStorageContainer() throws Exception {
-        StorageContainerResponse response = createDeleteResponse(StatusCode.SUCCESS);
-        StorageContainerRequest request = createDeleteRequest(ROOT_STORAGE_CONTAINER_ID);
+        DeleteRangeResponse response = createDeleteResponse(StatusCode.SUCCESS);
+        DeleteRangeRequest request = createDeleteRequest();
 
         when(mockRangeStoreService.delete(request))
             .thenReturn(CompletableFuture.completedFuture(response));
 
-        CompletableFuture<StorageContainerResponse> future = fromListenableFuture(
+        CompletableFuture<DeleteRangeResponse> future = fromListenableFuture(
             tableService.delete(request));
         verify(mockRangeStoreService, times(1)).delete(eq(request));
         assertTrue(response == future.get());
@@ -569,13 +558,13 @@ public class TestStorageContainerStoreImpl {
 
     @Test
     public void testPutMockStorageContainer() throws Exception {
-        StorageContainerResponse response = createPutResponse(StatusCode.SUCCESS);
-        StorageContainerRequest request = createPutRequest(ROOT_STORAGE_CONTAINER_ID);
+        PutResponse response = createPutResponse(StatusCode.SUCCESS);
+        PutRequest request = createPutRequest();
 
         when(mockRangeStoreService.put(request))
             .thenReturn(CompletableFuture.completedFuture(response));
 
-        CompletableFuture<StorageContainerResponse> future = fromListenableFuture(
+        CompletableFuture<PutResponse> future = fromListenableFuture(
             tableService.put(request));
         verify(mockRangeStoreService, times(1)).put(eq(request));
         assertTrue(response == future.get());
diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcMetaRangeService.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcMetaRangeService.java
index 178ac19..3f87b9e 100644
--- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcMetaRangeService.java
+++ b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcMetaRangeService.java
@@ -30,8 +30,6 @@ import org.apache.bookkeeper.common.concurrent.FutureUtils;
 import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesRequest;
 import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesResponse;
 import org.apache.bookkeeper.stream.proto.storage.StatusCode;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
 import org.apache.bookkeeper.stream.storage.api.metadata.RangeStoreService;
 import org.junit.Test;
 
@@ -51,23 +49,19 @@ public class TestGrpcMetaRangeService {
         RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcMetaRangeService grpcService = new GrpcMetaRangeService(rangeService);
 
-        StorageContainerRequest request = StorageContainerRequest
+        GetActiveRangesRequest request = GetActiveRangesRequest
             .newBuilder()
-            .setGetActiveRangesReq(GetActiveRangesRequest
-                .newBuilder()
-                .setStreamId(23456L)
-                .build())
+            .setStreamId(23456L)
             .build();
 
-        StorageContainerResponse response = StorageContainerResponse.newBuilder()
+        GetActiveRangesResponse response = GetActiveRangesResponse.newBuilder()
             .setCode(StatusCode.SUCCESS)
-            .setGetActiveRangesResp(GetActiveRangesResponse.newBuilder())
             .build();
 
         when(rangeService.getActiveRanges(request)).thenReturn(
             CompletableFuture.completedFuture(response));
 
-        TestResponseObserver<StorageContainerResponse> responseObserver =
+        TestResponseObserver<GetActiveRangesResponse> responseObserver =
             new TestResponseObserver<>();
         grpcService.getActiveRanges(
             request,
@@ -82,22 +76,19 @@ public class TestGrpcMetaRangeService {
         RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcMetaRangeService grpcService = new GrpcMetaRangeService(rangeService);
 
-        StorageContainerRequest request = StorageContainerRequest
+        GetActiveRangesRequest request = GetActiveRangesRequest
             .newBuilder()
-            .setGetActiveRangesReq(GetActiveRangesRequest
-                .newBuilder()
-                .setStreamId(23456L)
-                .build())
+            .setStreamId(23456L)
             .build();
 
-        StorageContainerResponse response = StorageContainerResponse.newBuilder()
+        GetActiveRangesResponse response = GetActiveRangesResponse.newBuilder()
             .setCode(StatusCode.INTERNAL_SERVER_ERROR)
             .build();
 
         when(rangeService.getActiveRanges(request)).thenReturn(
             FutureUtils.exception(CAUSE));
 
-        TestResponseObserver<StorageContainerResponse> responseObserver =
+        TestResponseObserver<GetActiveRangesResponse> responseObserver =
             new TestResponseObserver<>();
         grpcService.getActiveRanges(
             request,
@@ -112,18 +103,15 @@ public class TestGrpcMetaRangeService {
         RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcMetaRangeService grpcService = new GrpcMetaRangeService(rangeService);
 
-        StorageContainerRequest request = StorageContainerRequest
+        GetActiveRangesRequest request = GetActiveRangesRequest
             .newBuilder()
-            .setGetActiveRangesReq(GetActiveRangesRequest
-                .newBuilder()
-                .setStreamId(23456L)
-                .build())
+            .setStreamId(23456L)
             .build();
 
         when(rangeService.getActiveRanges(request)).thenReturn(
             FutureUtils.exception(new StatusRuntimeException(Status.NOT_FOUND)));
 
-        TestResponseObserver<StorageContainerResponse> responseObserver =
+        TestResponseObserver<GetActiveRangesResponse> responseObserver =
             new TestResponseObserver<>();
         grpcService.getActiveRanges(
             request,
diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcTableService.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcTableService.java
index e943fb4..874e69b 100644
--- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcTableService.java
+++ b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcTableService.java
@@ -34,10 +34,9 @@ import org.apache.bookkeeper.stream.proto.kv.rpc.PutRequest;
 import org.apache.bookkeeper.stream.proto.kv.rpc.PutResponse;
 import org.apache.bookkeeper.stream.proto.kv.rpc.RangeRequest;
 import org.apache.bookkeeper.stream.proto.kv.rpc.RangeResponse;
+import org.apache.bookkeeper.stream.proto.kv.rpc.ResponseHeader;
 import org.apache.bookkeeper.stream.proto.kv.rpc.RoutingHeader;
 import org.apache.bookkeeper.stream.proto.storage.StatusCode;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
 import org.apache.bookkeeper.stream.storage.api.metadata.RangeStoreService;
 import org.junit.Test;
 
@@ -66,24 +65,24 @@ public class TestGrpcTableService {
         RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcTableService grpcService = new GrpcTableService(rangeService);
 
-        StorageContainerRequest request = StorageContainerRequest
+        PutRequest request = PutRequest
             .newBuilder()
-            .setKvPutReq(PutRequest
-                .newBuilder()
-                .setKey(TEST_KEY)
-                .setValue(TEST_VAL)
-                .setHeader(ROUTING_HEADER))
+            .setKey(TEST_KEY)
+            .setValue(TEST_VAL)
+            .setHeader(ROUTING_HEADER)
             .build();
 
-        StorageContainerResponse response = StorageContainerResponse.newBuilder()
-            .setCode(StatusCode.SUCCESS)
-            .setKvPutResp(PutResponse.newBuilder())
+        PutResponse response = PutResponse.newBuilder()
+            .setHeader(ResponseHeader.newBuilder()
+                .setCode(StatusCode.SUCCESS)
+                .setRoutingHeader(ROUTING_HEADER)
+                .build())
             .build();
 
         when(rangeService.put(request)).thenReturn(
             CompletableFuture.completedFuture(response));
 
-        TestResponseObserver<StorageContainerResponse> responseObserver =
+        TestResponseObserver<PutResponse> responseObserver =
             new TestResponseObserver<>();
         grpcService.put(
             request,
@@ -98,23 +97,24 @@ public class TestGrpcTableService {
         RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcTableService grpcService = new GrpcTableService(rangeService);
 
-        StorageContainerRequest request = StorageContainerRequest
+        PutRequest request = PutRequest
             .newBuilder()
-            .setKvPutReq(PutRequest
-                .newBuilder()
-                .setKey(TEST_KEY)
-                .setValue(TEST_VAL)
-                .setHeader(ROUTING_HEADER))
+            .setKey(TEST_KEY)
+            .setValue(TEST_VAL)
+            .setHeader(ROUTING_HEADER)
             .build();
 
-        StorageContainerResponse response = StorageContainerResponse.newBuilder()
-            .setCode(StatusCode.INTERNAL_SERVER_ERROR)
+        PutResponse response = PutResponse.newBuilder()
+            .setHeader(ResponseHeader.newBuilder()
+                .setCode(StatusCode.INTERNAL_SERVER_ERROR)
+                .setRoutingHeader(ROUTING_HEADER)
+                .build())
             .build();
 
         when(rangeService.put(request)).thenReturn(
             FutureUtils.exception(CAUSE));
 
-        TestResponseObserver<StorageContainerResponse> responseObserver =
+        TestResponseObserver<PutResponse> responseObserver =
             new TestResponseObserver<>();
         grpcService.put(
             request,
@@ -129,19 +129,17 @@ public class TestGrpcTableService {
         RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcTableService grpcService = new GrpcTableService(rangeService);
 
-        StorageContainerRequest request = StorageContainerRequest
+        PutRequest request = PutRequest
             .newBuilder()
-            .setKvPutReq(PutRequest
-                .newBuilder()
-                .setKey(TEST_KEY)
-                .setValue(TEST_VAL)
-                .setHeader(ROUTING_HEADER))
+            .setKey(TEST_KEY)
+            .setValue(TEST_VAL)
+            .setHeader(ROUTING_HEADER)
             .build();
 
         when(rangeService.put(request)).thenReturn(
             FutureUtils.exception(new StatusRuntimeException(Status.NOT_FOUND)));
 
-        TestResponseObserver<StorageContainerResponse> responseObserver =
+        TestResponseObserver<PutResponse> responseObserver =
             new TestResponseObserver<>();
         grpcService.put(
             request,
@@ -156,23 +154,23 @@ public class TestGrpcTableService {
         RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcTableService grpcService = new GrpcTableService(rangeService);
 
-        StorageContainerRequest request = StorageContainerRequest
+        RangeRequest request = RangeRequest
             .newBuilder()
-            .setKvRangeReq(RangeRequest
-                .newBuilder()
-                .setKey(TEST_KEY)
-                .setHeader(ROUTING_HEADER))
+            .setKey(TEST_KEY)
+            .setHeader(ROUTING_HEADER)
             .build();
 
-        StorageContainerResponse response = StorageContainerResponse.newBuilder()
-            .setCode(StatusCode.SUCCESS)
-            .setKvRangeResp(RangeResponse.newBuilder())
+        RangeResponse response = RangeResponse.newBuilder()
+            .setHeader(ResponseHeader.newBuilder()
+                .setCode(StatusCode.SUCCESS)
+                .setRoutingHeader(ROUTING_HEADER)
+                .build())
             .build();
 
         when(rangeService.range(request)).thenReturn(
             CompletableFuture.completedFuture(response));
 
-        TestResponseObserver<StorageContainerResponse> responseObserver =
+        TestResponseObserver<RangeResponse> responseObserver =
             new TestResponseObserver<>();
         grpcService.range(
             request,
@@ -187,22 +185,23 @@ public class TestGrpcTableService {
         RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcTableService grpcService = new GrpcTableService(rangeService);
 
-        StorageContainerRequest request = StorageContainerRequest
+        RangeRequest request = RangeRequest
             .newBuilder()
-            .setKvRangeReq(RangeRequest
-                .newBuilder()
-                .setKey(TEST_KEY)
-                .setHeader(ROUTING_HEADER))
+            .setKey(TEST_KEY)
+            .setHeader(ROUTING_HEADER)
             .build();
 
-        StorageContainerResponse response = StorageContainerResponse.newBuilder()
-            .setCode(StatusCode.INTERNAL_SERVER_ERROR)
+        RangeResponse response = RangeResponse.newBuilder()
+            .setHeader(ResponseHeader.newBuilder()
+                .setCode(StatusCode.INTERNAL_SERVER_ERROR)
+                .setRoutingHeader(ROUTING_HEADER)
+                .build())
             .build();
 
         when(rangeService.range(request)).thenReturn(
             FutureUtils.exception(CAUSE));
 
-        TestResponseObserver<StorageContainerResponse> responseObserver =
+        TestResponseObserver<RangeResponse> responseObserver =
             new TestResponseObserver<>();
         grpcService.range(
             request,
@@ -217,18 +216,16 @@ public class TestGrpcTableService {
         RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcTableService grpcService = new GrpcTableService(rangeService);
 
-        StorageContainerRequest request = StorageContainerRequest
+        RangeRequest request = RangeRequest
             .newBuilder()
-            .setKvRangeReq(RangeRequest
-                .newBuilder()
-                .setKey(TEST_KEY)
-                .setHeader(ROUTING_HEADER))
+            .setKey(TEST_KEY)
+            .setHeader(ROUTING_HEADER)
             .build();
 
         when(rangeService.range(request)).thenReturn(
             FutureUtils.exception(new StatusRuntimeException(Status.NOT_FOUND)));
 
-        TestResponseObserver<StorageContainerResponse> responseObserver =
+        TestResponseObserver<RangeResponse> responseObserver =
             new TestResponseObserver<>();
         grpcService.range(
             request,
@@ -243,23 +240,23 @@ public class TestGrpcTableService {
         RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcTableService grpcService = new GrpcTableService(rangeService);
 
-        StorageContainerRequest request = StorageContainerRequest
+        DeleteRangeRequest request = DeleteRangeRequest
             .newBuilder()
-            .setKvDeleteReq(DeleteRangeRequest
-                .newBuilder()
-                .setKey(TEST_KEY)
-                .setHeader(ROUTING_HEADER))
+            .setKey(TEST_KEY)
+            .setHeader(ROUTING_HEADER)
             .build();
 
-        StorageContainerResponse response = StorageContainerResponse.newBuilder()
-            .setCode(StatusCode.SUCCESS)
-            .setKvDeleteResp(DeleteRangeResponse.newBuilder())
+        DeleteRangeResponse response = DeleteRangeResponse.newBuilder()
+            .setHeader(ResponseHeader.newBuilder()
+                .setCode(StatusCode.SUCCESS)
+                .setRoutingHeader(ROUTING_HEADER)
+                .build())
             .build();
 
         when(rangeService.delete(request)).thenReturn(
             CompletableFuture.completedFuture(response));
 
-        TestResponseObserver<StorageContainerResponse> responseObserver =
+        TestResponseObserver<DeleteRangeResponse> responseObserver =
             new TestResponseObserver<>();
         grpcService.delete(
             request,
@@ -274,22 +271,23 @@ public class TestGrpcTableService {
         RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcTableService grpcService = new GrpcTableService(rangeService);
 
-        StorageContainerRequest request = StorageContainerRequest
+        DeleteRangeRequest request = DeleteRangeRequest
             .newBuilder()
-            .setKvDeleteReq(DeleteRangeRequest
-                .newBuilder()
-                .setKey(TEST_KEY)
-                .setHeader(ROUTING_HEADER))
+            .setKey(TEST_KEY)
+            .setHeader(ROUTING_HEADER)
             .build();
 
-        StorageContainerResponse response = StorageContainerResponse.newBuilder()
-            .setCode(StatusCode.INTERNAL_SERVER_ERROR)
+        DeleteRangeResponse response = DeleteRangeResponse.newBuilder()
+            .setHeader(ResponseHeader.newBuilder()
+                .setCode(StatusCode.INTERNAL_SERVER_ERROR)
+                .setRoutingHeader(ROUTING_HEADER)
+                .build())
             .build();
 
         when(rangeService.delete(request)).thenReturn(
             FutureUtils.exception(CAUSE));
 
-        TestResponseObserver<StorageContainerResponse> responseObserver =
+        TestResponseObserver<DeleteRangeResponse> responseObserver =
             new TestResponseObserver<>();
         grpcService.delete(
             request,
@@ -304,18 +302,16 @@ public class TestGrpcTableService {
         RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcTableService grpcService = new GrpcTableService(rangeService);
 
-        StorageContainerRequest request = StorageContainerRequest
+        DeleteRangeRequest request = DeleteRangeRequest
             .newBuilder()
-            .setKvDeleteReq(DeleteRangeRequest
-                .newBuilder()
-                .setKey(TEST_KEY)
-                .setHeader(ROUTING_HEADER))
+            .setKey(TEST_KEY)
+            .setHeader(ROUTING_HEADER)
             .build();
 
         when(rangeService.delete(request)).thenReturn(
             FutureUtils.exception(new StatusRuntimeException(Status.NOT_FOUND)));
 
-        TestResponseObserver<StorageContainerResponse> responseObserver =
+        TestResponseObserver<DeleteRangeResponse> responseObserver =
             new TestResponseObserver<>();
         grpcService.delete(
             request,
diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/handler/TestStorageContainerResponseHandler.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/handler/TestStorageContainerResponseHandler.java
deleted file mode 100644
index 3eb440a..0000000
--- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/handler/TestStorageContainerResponseHandler.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.bookkeeper.stream.storage.impl.grpc.handler;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import io.grpc.Status;
-import io.grpc.StatusException;
-import io.grpc.StatusRuntimeException;
-import io.grpc.stub.StreamObserver;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicReference;
-import org.apache.bookkeeper.stream.proto.storage.StatusCode;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
-import org.apache.bookkeeper.stream.storage.exceptions.StorageException;
-import org.junit.Test;
-import org.mockito.stubbing.Answer;
-
-/**
- * Unit test for {@link StorageContainerResponseHandler}.
- */
-public class TestStorageContainerResponseHandler {
-
-    @SuppressWarnings("unchecked")
-    @Test
-    public void testSuccessResponse() {
-        StreamObserver<StorageContainerResponse> observer =
-            mock(StreamObserver.class);
-        StorageContainerResponseHandler handler = StorageContainerResponseHandler.of(observer);
-        StorageContainerResponse response = StorageContainerResponse.newBuilder()
-            .setCode(StatusCode.SUCCESS)
-            .build();
-        handler.accept(response, null);
-        verify(observer, times(1)).onNext(response);
-        verify(observer, times(1)).onCompleted();
-        verify(observer, times(0)).onError(any());
-    }
-
-    @SuppressWarnings("unchecked")
-    @Test
-    public void testStatusRuntimeException() {
-        StreamObserver<StorageContainerResponse> observer =
-            mock(StreamObserver.class);
-        StorageContainerResponseHandler handler = StorageContainerResponseHandler.of(observer);
-        StatusRuntimeException exception = new StatusRuntimeException(Status.NOT_FOUND);
-        handler.accept(null, exception);
-        verify(observer, times(0)).onNext(any());
-        verify(observer, times(0)).onCompleted();
-        verify(observer, times(1)).onError(exception);
-    }
-
-    @SuppressWarnings("unchecked")
-    @Test
-    public void testStatusException() {
-        StreamObserver<StorageContainerResponse> observer =
-            mock(StreamObserver.class);
-        StorageContainerResponseHandler handler = StorageContainerResponseHandler.of(observer);
-        StatusException exception = new StatusException(Status.NOT_FOUND);
-        handler.accept(null, exception);
-        verify(observer, times(0)).onNext(any());
-        verify(observer, times(0)).onCompleted();
-        verify(observer, times(1)).onError(exception);
-    }
-
-    @SuppressWarnings("unchecked")
-    @Test
-    public void testInternalError() throws Exception {
-        StreamObserver<StorageContainerResponse> observer =
-            mock(StreamObserver.class);
-        AtomicReference<StorageContainerResponse> responseHolder =
-            new AtomicReference<>(null);
-        CountDownLatch latch = new CountDownLatch(1);
-        doAnswer((Answer<Void>) invocation -> {
-            StorageContainerResponse resp = invocation.getArgument(0);
-            responseHolder.set(resp);
-            latch.countDown();
-            return null;
-        }).when(observer).onNext(any(StorageContainerResponse.class));
-        StorageContainerResponseHandler handler = StorageContainerResponseHandler.of(observer);
-        StorageException exception = new StorageException("test-exception");
-        handler.accept(null, exception);
-        verify(observer, times(1)).onNext(any());
-        verify(observer, times(1)).onCompleted();
-        verify(observer, times(0)).onError(any());
-
-        latch.await();
-        assertNotNull(responseHolder.get());
-        assertEquals(
-            StatusCode.INTERNAL_SERVER_ERROR,
-            responseHolder.get().getCode());
-    }
-
-}
diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/kv/TableStoreImplTest.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/kv/TableStoreImplTest.java
index f7b88fc..2c7124f 100644
--- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/kv/TableStoreImplTest.java
+++ b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/kv/TableStoreImplTest.java
@@ -46,9 +46,6 @@ import org.apache.bookkeeper.stream.proto.kv.rpc.RoutingHeader;
 import org.apache.bookkeeper.stream.proto.kv.rpc.TxnRequest;
 import org.apache.bookkeeper.stream.proto.kv.rpc.TxnResponse;
 import org.apache.bookkeeper.stream.proto.storage.StatusCode;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse.ResponseCase;
 import org.apache.bookkeeper.stream.storage.impl.store.MVCCAsyncStoreTestBase;
 import org.junit.Test;
 
@@ -90,16 +87,14 @@ public class TableStoreImplTest extends MVCCAsyncStoreTestBase {
     }
 
     private List<KeyValue> writeKVs(int numPairs, boolean prevKv) throws Exception {
-        List<CompletableFuture<StorageContainerResponse>> results =
+        List<CompletableFuture<PutResponse>> results =
             Lists.newArrayListWithExpectedSize(numPairs);
         for (int i = 0; i < numPairs; i++) {
             results.add(writeKV(i, prevKv));
         }
         return Lists.transform(
-            result(FutureUtils.collect(results)), response -> {
-                assertEquals(StatusCode.SUCCESS, response.getCode());
-                assertEquals(ResponseCase.KV_PUT_RESP, response.getResponseCase());
-                PutResponse putResp = response.getKvPutResp();
+            result(FutureUtils.collect(results)), putResp -> {
+                assertEquals(StatusCode.SUCCESS, putResp.getHeader().getCode());
                 assertEquals(HEADER, putResp.getHeader().getRoutingHeader());
                 if (putResp.hasPrevKv()) {
                     return putResp.getPrevKv();
@@ -109,33 +104,26 @@ public class TableStoreImplTest extends MVCCAsyncStoreTestBase {
             });
     }
 
-    private CompletableFuture<StorageContainerResponse> writeKV(int i, boolean prevKv) {
-        return tableStore.put(StorageContainerRequest.newBuilder()
-            .setScId(SC_ID)
-            .setKvPutReq(PutRequest.newBuilder()
-                .setKey(getKey(i))
-                .setValue(getValue(i))
-                .setHeader(HEADER)
-                .setPrevKv(prevKv))
+    private CompletableFuture<PutResponse> writeKV(int i, boolean prevKv) {
+        return tableStore.put(PutRequest.newBuilder()
+            .setKey(getKey(i))
+            .setValue(getValue(i))
+            .setHeader(HEADER)
+            .setPrevKv(prevKv)
             .build());
     }
 
-    StorageContainerResponse getKeyFromTableStore(int i) throws Exception {
+    RangeResponse getKeyFromTableStore(int i) throws Exception {
         return result(
-            tableStore.range(StorageContainerRequest.newBuilder()
-                .setScId(SC_ID)
-                .setKvRangeReq(RangeRequest.newBuilder()
-                    .setHeader(HEADER)
-                    .setKey(getKey(i))
-                    .build())
+            tableStore.range(RangeRequest.newBuilder()
+                .setHeader(HEADER)
+                .setKey(getKey(i))
                 .build()));
     }
 
     KeyValue getKeyValue(int i) throws Exception {
-        StorageContainerResponse resp = getKeyFromTableStore(i);
-        assertEquals(StatusCode.SUCCESS, resp.getCode());
-        assertEquals(ResponseCase.KV_RANGE_RESP, resp.getResponseCase());
-        RangeResponse rr = resp.getKvRangeResp();
+        RangeResponse rr = getKeyFromTableStore(i);
+        assertEquals(StatusCode.SUCCESS, rr.getHeader().getCode());
         assertEquals(HEADER, rr.getHeader().getRoutingHeader());
         assertFalse(rr.getMore());
         if (0 == rr.getCount()) {
@@ -146,53 +134,43 @@ public class TableStoreImplTest extends MVCCAsyncStoreTestBase {
     }
 
     void putKeyToTableStore(int key, int value) throws Exception {
-        StorageContainerResponse response = result(
-            tableStore.put(StorageContainerRequest.newBuilder()
-                .setScId(SC_ID)
-                .setKvPutReq(PutRequest.newBuilder()
-                    .setHeader(HEADER)
-                    .setKey(getKey(key))
-                    .setValue(getValue(value))
-                    .build())
+        PutResponse putResp = result(
+            tableStore.put(PutRequest.newBuilder()
+                .setHeader(HEADER)
+                .setKey(getKey(key))
+                .setValue(getValue(value))
                 .build()));
 
-        assertEquals(StatusCode.SUCCESS, response.getCode());
-        assertEquals(ResponseCase.KV_PUT_RESP, response.getResponseCase());
-        PutResponse putResp = response.getKvPutResp();
+        assertEquals(StatusCode.SUCCESS, putResp.getHeader().getCode());
         assertEquals(HEADER, putResp.getHeader().getRoutingHeader());
         assertFalse(putResp.hasPrevKv());
     }
 
     KeyValue putIfAbsentToTableStore(int key, int value, boolean expectedSuccess) throws Exception {
-        StorageContainerResponse response = result(
-            tableStore.txn(StorageContainerRequest.newBuilder()
-                .setScId(SC_ID)
-                .setKvTxnReq(TxnRequest.newBuilder()
-                    .setHeader(HEADER)
-                    .addCompare(Compare.newBuilder()
-                        .setResult(CompareResult.EQUAL)
-                        .setTarget(CompareTarget.VALUE)
+        TxnResponse txnResp = result(
+            tableStore.txn(TxnRequest.newBuilder()
+                .setHeader(HEADER)
+                .addCompare(Compare.newBuilder()
+                    .setResult(CompareResult.EQUAL)
+                    .setTarget(CompareTarget.VALUE)
+                    .setKey(getKey(key))
+                    .setValue(ByteString.copyFrom(new byte[0])))
+                .addSuccess(RequestOp.newBuilder()
+                    .setRequestPut(PutRequest.newBuilder()
+                        .setHeader(HEADER)
                         .setKey(getKey(key))
-                        .setValue(ByteString.copyFrom(new byte[0])))
-                    .addSuccess(RequestOp.newBuilder()
-                        .setRequestPut(PutRequest.newBuilder()
-                            .setHeader(HEADER)
-                            .setKey(getKey(key))
-                            .setValue(getValue(value))
-                            .setPrevKv(true)
-                            .build()))
-                    .addFailure(RequestOp.newBuilder()
-                        .setRequestRange(RangeRequest.newBuilder()
-                            .setHeader(HEADER)
-                            .setKey(getKey(key))
-                            .build()))
-                    .build())
+                        .setValue(getValue(value))
+                        .setPrevKv(true)
+                        .build()))
+                .addFailure(RequestOp.newBuilder()
+                    .setRequestRange(RangeRequest.newBuilder()
+                        .setHeader(HEADER)
+                        .setKey(getKey(key))
+                        .build()))
                 .build()));
 
-        assertEquals(ResponseCase.KV_TXN_RESP, response.getResponseCase());
-        TxnResponse txnResp = response.getKvTxnResp();
         assertEquals(HEADER, txnResp.getHeader().getRoutingHeader());
-        assertEquals(StatusCode.SUCCESS, response.getCode());
+        assertEquals(StatusCode.SUCCESS, txnResp.getHeader().getCode());
 
         ResponseOp respOp = txnResp.getResponses(0);
         if (expectedSuccess) {
@@ -215,39 +193,34 @@ public class TableStoreImplTest extends MVCCAsyncStoreTestBase {
         }
     }
 
-    StorageContainerResponse vPutToTableStore(int key, int value, long version)
+    TxnResponse vPutToTableStore(int key, int value, long version)
         throws Exception {
         return result(
-            tableStore.txn(StorageContainerRequest.newBuilder()
-                .setScId(SC_ID)
-                .setKvTxnReq(TxnRequest.newBuilder()
-                    .setHeader(HEADER)
-                    .addCompare(Compare.newBuilder()
-                        .setResult(CompareResult.EQUAL)
-                        .setTarget(CompareTarget.VERSION)
+            tableStore.txn(TxnRequest.newBuilder()
+                .setHeader(HEADER)
+                .addCompare(Compare.newBuilder()
+                    .setResult(CompareResult.EQUAL)
+                    .setTarget(CompareTarget.VERSION)
+                    .setKey(getKey(key))
+                    .setVersion(version))
+                .addSuccess(RequestOp.newBuilder()
+                    .setRequestPut(PutRequest.newBuilder()
+                        .setHeader(HEADER)
+                        .setKey(getKey(key))
+                        .setValue(getValue(value))
+                        .setPrevKv(true)
+                        .build()))
+                .addFailure(RequestOp.newBuilder()
+                    .setRequestRange(RangeRequest.newBuilder()
+                        .setHeader(HEADER)
                         .setKey(getKey(key))
-                        .setVersion(version))
-                    .addSuccess(RequestOp.newBuilder()
-                        .setRequestPut(PutRequest.newBuilder()
-                            .setHeader(HEADER)
-                            .setKey(getKey(key))
-                            .setValue(getValue(value))
-                            .setPrevKv(true)
-                            .build()))
-                    .addFailure(RequestOp.newBuilder()
-                        .setRequestRange(RangeRequest.newBuilder()
-                            .setHeader(HEADER)
-                            .setKey(getKey(key))
-                            .build()))
-                    .build())
+                        .build()))
                 .build()));
     }
 
-    KeyValue verifyVPutResponse(StorageContainerResponse response, boolean expectedSuccess) throws Exception {
-        assertEquals(ResponseCase.KV_TXN_RESP, response.getResponseCase());
-        TxnResponse txnResp = response.getKvTxnResp();
+    KeyValue verifyVPutResponse(TxnResponse txnResp, boolean expectedSuccess) throws Exception {
         assertEquals(HEADER, txnResp.getHeader().getRoutingHeader());
-        assertEquals(StatusCode.SUCCESS, response.getCode());
+        assertEquals(StatusCode.SUCCESS, txnResp.getHeader().getCode());
 
         ResponseOp respOp = txnResp.getResponses(0);
         if (expectedSuccess) {
@@ -270,89 +243,71 @@ public class TableStoreImplTest extends MVCCAsyncStoreTestBase {
         }
     }
 
-    StorageContainerResponse rPutToTableStore(int key, int value, long revision)
+    TxnResponse rPutToTableStore(int key, int value, long revision)
         throws Exception {
         return result(
-            tableStore.txn(StorageContainerRequest.newBuilder()
-                .setScId(SC_ID)
-                .setKvTxnReq(TxnRequest.newBuilder()
-                    .setHeader(HEADER)
-                    .addCompare(Compare.newBuilder()
-                        .setResult(CompareResult.EQUAL)
-                        .setTarget(CompareTarget.MOD)
+            tableStore.txn(TxnRequest.newBuilder()
+                .setHeader(HEADER)
+                .addCompare(Compare.newBuilder()
+                    .setResult(CompareResult.EQUAL)
+                    .setTarget(CompareTarget.MOD)
+                    .setKey(getKey(key))
+                    .setModRevision(revision))
+                .addSuccess(RequestOp.newBuilder()
+                    .setRequestPut(PutRequest.newBuilder()
+                        .setHeader(HEADER)
+                        .setKey(getKey(key))
+                        .setValue(getValue(value))
+                        .setPrevKv(true)
+                        .build()))
+                .addFailure(RequestOp.newBuilder()
+                    .setRequestRange(RangeRequest.newBuilder()
+                        .setHeader(HEADER)
                         .setKey(getKey(key))
-                        .setModRevision(revision))
-                    .addSuccess(RequestOp.newBuilder()
-                        .setRequestPut(PutRequest.newBuilder()
-                            .setHeader(HEADER)
-                            .setKey(getKey(key))
-                            .setValue(getValue(value))
-                            .setPrevKv(true)
-                            .build()))
-                    .addFailure(RequestOp.newBuilder()
-                        .setRequestRange(RangeRequest.newBuilder()
-                            .setHeader(HEADER)
-                            .setKey(getKey(key))
-                            .build()))
-                    .build())
+                        .build()))
                 .build()));
     }
 
     KeyValue deleteKeyFromTableStore(int key) throws Exception {
-        StorageContainerResponse response = result(
-            tableStore.delete(StorageContainerRequest.newBuilder()
-                .setScId(SC_ID)
-                .setKvDeleteReq(DeleteRangeRequest.newBuilder()
-                    .setHeader(HEADER)
-                    .setKey(getKey(key))
-                    .setPrevKv(true)
-                    .build())
+        DeleteRangeResponse response = result(
+            tableStore.delete(DeleteRangeRequest.newBuilder()
+                .setHeader(HEADER)
+                .setKey(getKey(key))
+                .setPrevKv(true)
                 .build()));
 
-        assertEquals(StatusCode.SUCCESS, response.getCode());
-        assertEquals(ResponseCase.KV_DELETE_RESP, response.getResponseCase());
-        DeleteRangeResponse delResp = response.getKvDeleteResp();
-        assertEquals(HEADER, delResp.getHeader().getRoutingHeader());
-        if (0 == delResp.getPrevKvsCount()) {
+        assertEquals(StatusCode.SUCCESS, response.getHeader().getCode());
+        assertEquals(HEADER, response.getHeader().getRoutingHeader());
+        if (0 == response.getPrevKvsCount()) {
             return null;
         } else {
-            return delResp.getPrevKvs(0);
+            return response.getPrevKvs(0);
         }
     }
 
     List<KeyValue> deleteRange(int startKey, int endKey) throws Exception {
-        StorageContainerResponse response = result(
-            tableStore.delete(StorageContainerRequest.newBuilder()
-                .setScId(SC_ID)
-                .setKvDeleteReq(DeleteRangeRequest.newBuilder()
-                    .setHeader(HEADER)
-                    .setKey(getKey(startKey))
-                    .setRangeEnd(getKey(endKey))
-                    .setPrevKv(true)
-                    .build())
+        DeleteRangeResponse delResp = result(
+            tableStore.delete(DeleteRangeRequest.newBuilder()
+                .setHeader(HEADER)
+                .setKey(getKey(startKey))
+                .setRangeEnd(getKey(endKey))
+                .setPrevKv(true)
                 .build()));
 
-        assertEquals(StatusCode.SUCCESS, response.getCode());
-        assertEquals(ResponseCase.KV_DELETE_RESP, response.getResponseCase());
-        DeleteRangeResponse delResp = response.getKvDeleteResp();
+        assertEquals(StatusCode.SUCCESS, delResp.getHeader().getCode());
         assertEquals(HEADER, delResp.getHeader().getRoutingHeader());
         return delResp.getPrevKvsList();
     }
 
     List<KeyValue> range(int startKey, int endKey) throws Exception {
-        StorageContainerResponse response = result(
-            tableStore.range(StorageContainerRequest.newBuilder()
-                .setScId(SC_ID)
-                .setKvRangeReq(RangeRequest.newBuilder()
-                    .setHeader(HEADER)
-                    .setKey(getKey(startKey))
-                    .setRangeEnd(getKey(endKey))
-                    .build())
+        RangeResponse rangeResp = result(
+            tableStore.range(RangeRequest.newBuilder()
+                .setHeader(HEADER)
+                .setKey(getKey(startKey))
+                .setRangeEnd(getKey(endKey))
                 .build()));
 
-        assertEquals(StatusCode.SUCCESS, response.getCode());
-        assertEquals(ResponseCase.KV_RANGE_RESP, response.getResponseCase());
-        RangeResponse rangeResp = response.getKvRangeResp();
+        assertEquals(StatusCode.SUCCESS, rangeResp.getHeader().getCode());
         assertEquals(HEADER, rangeResp.getHeader().getRoutingHeader());
         return rangeResp.getKvsList();
     }
@@ -398,18 +353,18 @@ public class TableStoreImplTest extends MVCCAsyncStoreTestBase {
             int key = 2;
             int initialVal = 2;
             int casVal = 99;
-            StorageContainerResponse response = vPutToTableStore(key, initialVal, 100L);
-            assertEquals(StatusCode.KEY_NOT_FOUND, response.getCode());
+            TxnResponse response = vPutToTableStore(key, initialVal, 100L);
+            assertEquals(StatusCode.KEY_NOT_FOUND, response.getHeader().getCode());
 
             // vPut(k, v, -1L)
             response = vPutToTableStore(key, initialVal, -1L);
-            assertEquals(StatusCode.KEY_NOT_FOUND, response.getCode());
+            assertEquals(StatusCode.KEY_NOT_FOUND, response.getHeader().getCode());
             // put(key2, v)
             KeyValue prevKV = putIfAbsentToTableStore(key, initialVal, true);
             assertNull(prevKV);
             // vPut(key2, v, 0)
             response = vPutToTableStore(key, casVal, 0);
-            assertEquals(StatusCode.SUCCESS, response.getCode());
+            assertEquals(StatusCode.SUCCESS, response.getHeader().getCode());
             prevKV = verifyVPutResponse(response, true);
             assertNotNull(prevKV);
             assertEquals(getKey(key), prevKV.getKey());
@@ -428,12 +383,12 @@ public class TableStoreImplTest extends MVCCAsyncStoreTestBase {
             int initialVal = 3;
             int casVal = 99;
 
-            StorageContainerResponse response = rPutToTableStore(key, initialVal, 100L);
-            assertEquals(StatusCode.KEY_NOT_FOUND, response.getCode());
+            TxnResponse response = rPutToTableStore(key, initialVal, 100L);
+            assertEquals(StatusCode.KEY_NOT_FOUND, response.getHeader().getCode());
 
             // rPut(k, v, -1L)
             response = rPutToTableStore(key, initialVal, -1L);
-            assertEquals(StatusCode.KEY_NOT_FOUND, response.getCode());
+            assertEquals(StatusCode.KEY_NOT_FOUND, response.getHeader().getCode());
 
             // put(key2, v)
             KeyValue prevKV = putIfAbsentToTableStore(key, initialVal, true);
@@ -445,7 +400,7 @@ public class TableStoreImplTest extends MVCCAsyncStoreTestBase {
 
             // rPut(key2, v, 0)
             response = rPutToTableStore(key, casVal, revision);
-            assertEquals(StatusCode.SUCCESS, response.getCode());
+            assertEquals(StatusCode.SUCCESS, response.getHeader().getCode());
 
             kv = getKeyValue(key);
             assertEquals(revision + 1, kv.getModRevision());
diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/metadata/MetaRangeStoreImplTest.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/metadata/MetaRangeStoreImplTest.java
index d2ed9b6..d0156c5 100644
--- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/metadata/MetaRangeStoreImplTest.java
+++ b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/metadata/MetaRangeStoreImplTest.java
@@ -36,8 +36,6 @@ import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesRequest;
 import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesResponse;
 import org.apache.bookkeeper.stream.proto.storage.RelatedRanges;
 import org.apache.bookkeeper.stream.proto.storage.StatusCode;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
 import org.apache.bookkeeper.stream.storage.impl.metadata.stream.MetaRangeImpl;
 import org.apache.bookkeeper.stream.storage.impl.sc.StorageContainerPlacementPolicyImpl;
 import org.apache.bookkeeper.stream.storage.impl.store.MVCCAsyncStoreTestBase;
@@ -69,21 +67,18 @@ public class MetaRangeStoreImplTest extends MVCCAsyncStoreTestBase {
     protected void doTeardown() throws Exception {
     }
 
-    StorageContainerRequest createRequest(StreamProperties streamProperties) {
+    GetActiveRangesRequest createRequest(StreamProperties streamProperties) {
         GetActiveRangesRequest.Builder reqBuilder = GetActiveRangesRequest.newBuilder()
             .setStreamId(this.streamProps.getStreamId());
         if (null != streamProperties) {
             reqBuilder = reqBuilder.setStreamProps(streamProperties);
         }
-        return StorageContainerRequest.newBuilder()
-            .setGetActiveRangesReq(reqBuilder)
-            .setScId(1L)
-            .build();
+        return reqBuilder.build();
     }
 
     @Test
     public void testCreateIfMissingPropsNotSpecified() throws Exception {
-        StorageContainerResponse resp = FutureUtils.result(
+        GetActiveRangesResponse resp = FutureUtils.result(
             this.mrStoreImpl.getActiveRanges(createRequest(null)));
 
         assertEquals(StatusCode.STREAM_NOT_FOUND, resp.getCode());
@@ -91,13 +86,11 @@ public class MetaRangeStoreImplTest extends MVCCAsyncStoreTestBase {
 
     @Test
     public void testCreateIfMissing() throws Exception {
-        StorageContainerResponse resp = FutureUtils.result(
+        GetActiveRangesResponse resp = FutureUtils.result(
             this.mrStoreImpl.getActiveRanges(createRequest(streamProps)));
 
         assertEquals(StatusCode.SUCCESS, resp.getCode());
-        GetActiveRangesResponse getResp = resp.getGetActiveRangesResp();
-
-        verifyGetResponse(getResp);
+        verifyGetResponse(resp);
     }
 
     private void verifyGetResponse(GetActiveRangesResponse getResp) throws Exception {
@@ -222,22 +215,19 @@ public class MetaRangeStoreImplTest extends MVCCAsyncStoreTestBase {
 
     @Test
     public void testGetTwice() throws Exception {
-
-        StorageContainerResponse resp = FutureUtils.result(
+        GetActiveRangesResponse resp = FutureUtils.result(
             this.mrStoreImpl.getActiveRanges(createRequest(streamProps)));
 
         assertEquals(StatusCode.SUCCESS, resp.getCode());
 
-        GetActiveRangesResponse getResp = resp.getGetActiveRangesResp();
-        verifyGetResponse(getResp);
+        verifyGetResponse(resp);
 
-        StorageContainerResponse secondResp = FutureUtils.result(
+        GetActiveRangesResponse secondResp = FutureUtils.result(
             this.mrStoreImpl.getActiveRanges(createRequest(streamProps)));
 
         assertEquals(StatusCode.SUCCESS, secondResp.getCode());
 
-        GetActiveRangesResponse secondGetResp = resp.getGetActiveRangesResp();
-        verifyGetResponse(secondGetResp);
+        verifyGetResponse(secondResp);
     }
 
 }
diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreServiceImplTest.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreServiceImplTest.java
index a4d8710..2cbb27f 100644
--- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreServiceImplTest.java
+++ b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreServiceImplTest.java
@@ -17,10 +17,6 @@
  */
 package org.apache.bookkeeper.stream.storage.impl.service;
 
-import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_DELETE_REQ;
-import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_PUT_REQ;
-import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_RANGE_REQ;
-import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_TXN_REQ;
 import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.CONTAINER_META_RANGE_ID;
 import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.CONTAINER_META_STREAM_ID;
 import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.ROOT_RANGE_ID;
@@ -40,11 +36,15 @@ import org.apache.bookkeeper.common.concurrent.FutureUtils;
 import org.apache.bookkeeper.common.util.OrderedScheduler;
 import org.apache.bookkeeper.statelib.api.mvcc.MVCCAsyncStore;
 import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeResponse;
 import org.apache.bookkeeper.stream.proto.kv.rpc.IncrementRequest;
 import org.apache.bookkeeper.stream.proto.kv.rpc.PutRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.PutResponse;
 import org.apache.bookkeeper.stream.proto.kv.rpc.RangeRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.RangeResponse;
 import org.apache.bookkeeper.stream.proto.kv.rpc.RoutingHeader;
 import org.apache.bookkeeper.stream.proto.kv.rpc.TxnRequest;
+import org.apache.bookkeeper.stream.proto.kv.rpc.TxnResponse;
 import org.apache.bookkeeper.stream.proto.storage.CreateNamespaceRequest;
 import org.apache.bookkeeper.stream.proto.storage.CreateNamespaceResponse;
 import org.apache.bookkeeper.stream.proto.storage.CreateStreamRequest;
@@ -53,13 +53,12 @@ import org.apache.bookkeeper.stream.proto.storage.DeleteNamespaceRequest;
 import org.apache.bookkeeper.stream.proto.storage.DeleteNamespaceResponse;
 import org.apache.bookkeeper.stream.proto.storage.DeleteStreamRequest;
 import org.apache.bookkeeper.stream.proto.storage.DeleteStreamResponse;
+import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesRequest;
+import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesResponse;
 import org.apache.bookkeeper.stream.proto.storage.GetNamespaceRequest;
 import org.apache.bookkeeper.stream.proto.storage.GetNamespaceResponse;
 import org.apache.bookkeeper.stream.proto.storage.GetStreamRequest;
 import org.apache.bookkeeper.stream.proto.storage.GetStreamResponse;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
 import org.apache.bookkeeper.stream.protocol.RangeId;
 import org.apache.bookkeeper.stream.storage.api.kv.TableStore;
 import org.apache.bookkeeper.stream.storage.api.metadata.MetaRangeStore;
@@ -322,11 +321,11 @@ public class RangeStoreServiceImplTest {
     public void testGetActiveRanges() throws Exception {
         mockStorageContainer(SCID);
 
-        StorageContainerResponse expectedResp = StorageContainerResponse.getDefaultInstance();
-        when(mrStore.getActiveRanges(any(StorageContainerRequest.class)))
+        GetActiveRangesResponse expectedResp = GetActiveRangesResponse.getDefaultInstance();
+        when(mrStore.getActiveRanges(any(GetActiveRangesRequest.class)))
             .thenReturn(FutureUtils.value(expectedResp));
 
-        StorageContainerRequest expectedReq = StorageContainerRequest.getDefaultInstance();
+        GetActiveRangesRequest expectedReq = GetActiveRangesRequest.getDefaultInstance();
         assertSame(
             expectedResp,
             FutureUtils.result(mrStore.getActiveRanges(expectedReq)));
@@ -338,50 +337,66 @@ public class RangeStoreServiceImplTest {
     // Table API
     //
 
-    private StorageContainerRequest newStorageContainerRequest(RequestCase type) {
-        StorageContainerRequest.Builder reqBuilder = StorageContainerRequest.newBuilder()
-            .setScId(SCID);
+    private PutRequest newPutRequest() {
         RoutingHeader header = RoutingHeader.newBuilder()
             .setStreamId(STREAM_ID)
             .setRangeId(RANGE_ID)
             .build();
-        switch (type) {
-            case KV_PUT_REQ:
-                reqBuilder = reqBuilder.setKvPutReq(
-                    PutRequest.newBuilder().setHeader(header));
-                break;
-            case KV_DELETE_REQ:
-                reqBuilder = reqBuilder.setKvDeleteReq(
-                    DeleteRangeRequest.newBuilder().setHeader(header));
-                break;
-            case KV_RANGE_REQ:
-                reqBuilder = reqBuilder.setKvRangeReq(
-                    RangeRequest.newBuilder().setHeader(header));
-                break;
-            case KV_TXN_REQ:
-                reqBuilder = reqBuilder.setKvTxnReq(
-                    TxnRequest.newBuilder().setHeader(header));
-                break;
-            case KV_INCR_REQ:
-                reqBuilder = reqBuilder.setKvIncrReq(
-                    IncrementRequest.newBuilder().setHeader(header));
-                break;
-            default:
-                break;
-        }
-        return reqBuilder.build();
+        return PutRequest.newBuilder()
+            .setHeader(header)
+            .build();
+    }
+
+    private DeleteRangeRequest newDeleteRequest() {
+        RoutingHeader header = RoutingHeader.newBuilder()
+            .setStreamId(STREAM_ID)
+            .setRangeId(RANGE_ID)
+            .build();
+        return DeleteRangeRequest.newBuilder()
+            .setHeader(header)
+            .build();
+    }
+
+    private RangeRequest newRangeRequest() {
+        RoutingHeader header = RoutingHeader.newBuilder()
+            .setStreamId(STREAM_ID)
+            .setRangeId(RANGE_ID)
+            .build();
+        return RangeRequest.newBuilder()
+            .setHeader(header)
+            .build();
+    }
+
+    private IncrementRequest newIncrRequest() {
+        RoutingHeader header = RoutingHeader.newBuilder()
+            .setStreamId(STREAM_ID)
+            .setRangeId(RANGE_ID)
+            .build();
+        return IncrementRequest.newBuilder()
+            .setHeader(header)
+            .build();
+    }
+
+    private TxnRequest newTxnRequest() {
+        RoutingHeader header = RoutingHeader.newBuilder()
+            .setStreamId(STREAM_ID)
+            .setRangeId(RANGE_ID)
+            .build();
+        return TxnRequest.newBuilder()
+            .setHeader(header)
+            .build();
     }
 
     @Test
     public void testRangeWhenTableStoreNotCached() throws Exception {
         mockStorageContainer(SCID);
 
-        StorageContainerResponse expectedResp = StorageContainerResponse.getDefaultInstance();
-        when(trStore.range(any(StorageContainerRequest.class)))
+        RangeResponse expectedResp = RangeResponse.getDefaultInstance();
+        when(trStore.range(any(RangeRequest.class)))
             .thenReturn(FutureUtils.value(expectedResp));
 
-        StorageContainerRequest request = newStorageContainerRequest(KV_RANGE_REQ);
-        StorageContainerResponse response = FutureUtils.result(container.range(request));
+        RangeRequest request = newRangeRequest();
+        RangeResponse response = FutureUtils.result(container.range(request));
         assertSame(expectedResp, response);
         assertSame(trStore, container.getTableStoreCache().getTableStore(RID));
     }
@@ -390,13 +405,13 @@ public class RangeStoreServiceImplTest {
     public void testRangeWhenTableStoreCached() throws Exception {
         mockStorageContainer(SCID);
 
-        StorageContainerResponse expectedResp = StorageContainerResponse.getDefaultInstance();
-        when(trStore.range(any(StorageContainerRequest.class)))
+        RangeResponse expectedResp = RangeResponse.getDefaultInstance();
+        when(trStore.range(any(RangeRequest.class)))
             .thenReturn(FutureUtils.value(expectedResp));
         container.getTableStoreCache().getTableStores().put(RID, trStore);
 
-        StorageContainerRequest request = newStorageContainerRequest(KV_RANGE_REQ);
-        StorageContainerResponse response = FutureUtils.result(container.range(request));
+        RangeRequest request = newRangeRequest();
+        RangeResponse response = FutureUtils.result(container.range(request));
         assertSame(expectedResp, response);
     }
 
@@ -404,12 +419,12 @@ public class RangeStoreServiceImplTest {
     public void testPutWhenTableStoreNotCached() throws Exception {
         mockStorageContainer(SCID);
 
-        StorageContainerResponse expectedResp = StorageContainerResponse.getDefaultInstance();
-        when(trStore.put(any(StorageContainerRequest.class)))
+        PutResponse expectedResp = PutResponse.getDefaultInstance();
+        when(trStore.put(any(PutRequest.class)))
             .thenReturn(FutureUtils.value(expectedResp));
 
-        StorageContainerRequest request = newStorageContainerRequest(KV_PUT_REQ);
-        StorageContainerResponse response = FutureUtils.result(container.put(request));
+        PutRequest request = newPutRequest();
+        PutResponse response = FutureUtils.result(container.put(request));
         assertSame(expectedResp, response);
         assertSame(trStore, container.getTableStoreCache().getTableStore(RID));
     }
@@ -418,13 +433,13 @@ public class RangeStoreServiceImplTest {
     public void testPutWhenTableStoreCached() throws Exception {
         mockStorageContainer(SCID);
 
-        StorageContainerResponse expectedResp = StorageContainerResponse.getDefaultInstance();
-        when(trStore.put(any(StorageContainerRequest.class)))
+        PutResponse expectedResp = PutResponse.getDefaultInstance();
+        when(trStore.put(any(PutRequest.class)))
             .thenReturn(FutureUtils.value(expectedResp));
         container.getTableStoreCache().getTableStores().put(RID, trStore);
 
-        StorageContainerRequest request = newStorageContainerRequest(KV_PUT_REQ);
-        StorageContainerResponse response = FutureUtils.result(container.put(request));
+        PutRequest request = newPutRequest();
+        PutResponse response = FutureUtils.result(container.put(request));
         assertSame(expectedResp, response);
     }
 
@@ -432,12 +447,12 @@ public class RangeStoreServiceImplTest {
     public void testDeleteWhenTableStoreNotCached() throws Exception {
         mockStorageContainer(SCID);
 
-        StorageContainerResponse expectedResp = StorageContainerResponse.getDefaultInstance();
-        when(trStore.delete(any(StorageContainerRequest.class)))
+        DeleteRangeResponse expectedResp = DeleteRangeResponse.getDefaultInstance();
+        when(trStore.delete(any(DeleteRangeRequest.class)))
             .thenReturn(FutureUtils.value(expectedResp));
 
-        StorageContainerRequest request = newStorageContainerRequest(KV_DELETE_REQ);
-        StorageContainerResponse response = FutureUtils.result(container.delete(request));
+        DeleteRangeRequest request = newDeleteRequest();
+        DeleteRangeResponse response = FutureUtils.result(container.delete(request));
         assertSame(expectedResp, response);
         assertSame(trStore, container.getTableStoreCache().getTableStore(RID));
     }
@@ -446,13 +461,13 @@ public class RangeStoreServiceImplTest {
     public void testDeleteWhenTableStoreCached() throws Exception {
         mockStorageContainer(SCID);
 
-        StorageContainerResponse expectedResp = StorageContainerResponse.getDefaultInstance();
-        when(trStore.delete(any(StorageContainerRequest.class)))
+        DeleteRangeResponse expectedResp = DeleteRangeResponse.getDefaultInstance();
+        when(trStore.delete(any(DeleteRangeRequest.class)))
             .thenReturn(FutureUtils.value(expectedResp));
         container.getTableStoreCache().getTableStores().put(RID, trStore);
 
-        StorageContainerRequest request = newStorageContainerRequest(KV_DELETE_REQ);
-        StorageContainerResponse response = FutureUtils.result(container.delete(request));
+        DeleteRangeRequest request = newDeleteRequest();
+        DeleteRangeResponse response = FutureUtils.result(container.delete(request));
         assertSame(expectedResp, response);
     }
 
@@ -460,12 +475,12 @@ public class RangeStoreServiceImplTest {
     public void testTxnWhenTableStoreNotCached() throws Exception {
         mockStorageContainer(SCID);
 
-        StorageContainerResponse expectedResp = StorageContainerResponse.getDefaultInstance();
-        when(trStore.txn(any(StorageContainerRequest.class)))
+        TxnResponse expectedResp = TxnResponse.getDefaultInstance();
+        when(trStore.txn(any(TxnRequest.class)))
             .thenReturn(FutureUtils.value(expectedResp));
 
-        StorageContainerRequest request = newStorageContainerRequest(KV_TXN_REQ);
-        StorageContainerResponse response = FutureUtils.result(container.txn(request));
+        TxnRequest request = newTxnRequest();
+        TxnResponse response = FutureUtils.result(container.txn(request));
         assertSame(expectedResp, response);
         assertSame(trStore, container.getTableStoreCache().getTableStore(RID));
     }
@@ -474,13 +489,13 @@ public class RangeStoreServiceImplTest {
     public void testTxnWhenTableStoreCached() throws Exception {
         mockStorageContainer(SCID);
 
-        StorageContainerResponse expectedResp = StorageContainerResponse.getDefaultInstance();
-        when(trStore.txn(any(StorageContainerRequest.class)))
+        TxnResponse expectedResp = TxnResponse.getDefaultInstance();
+        when(trStore.txn(any(TxnRequest.class)))
             .thenReturn(FutureUtils.value(expectedResp));
         container.getTableStoreCache().getTableStores().put(RID, trStore);
 
-        StorageContainerRequest request = newStorageContainerRequest(KV_TXN_REQ);
-        StorageContainerResponse response = FutureUtils.result(container.txn(request));
+        TxnRequest request = newTxnRequest();
+        TxnResponse response = FutureUtils.result(container.txn(request));
         assertSame(expectedResp, response);
     }
 }

-- 
To stop receiving notification emails like this one, please contact
sijie@apache.org.

[bookkeeper] 08/09: [TABLE SERVICE] cleanup : provide unified service uri for resolving service endpoints

Posted by si...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sijie pushed a commit to branch branch-4.7
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git

commit 87f965587dc1df0b6f3877a037e5c120d1ec9c4a
Author: Sijie Guo <si...@apache.org>
AuthorDate: Thu May 31 23:24:02 2018 -0700

    [TABLE SERVICE] cleanup : provide unified service uri for resolving service endpoints
    
    Descriptions of the changes in this PR:
    
    *Motivation*
    
    Currently there are multiple settings in `StorageClientSettings` on configuring how to resolve
    service endpoints to find the services. It is a bit inconvinient and confusing
    
    *Solution*
    
    Provide a class `ServiceURI` for parsing service uri to retrieve common informations including:
    
    - serviceName
    - serviceInfos
    - serviceUser
    - serviceHosts
    - servicePath
    
    It extends the java.net.URI and does parsing and validation in the same place. Then it can be used
    by the grpc name resolver to resolve service endpoints.
    
    Also update dlog to use it for resolving its namespace uri.
    
    Author: Sijie Guo <si...@apache.org>
    
    Reviewers: Jia Zhai <None>
    
    This closes #1459 from sijie/name_resolver
---
 .../apache/bookkeeper/common/net/ServiceURI.java   | 235 +++++++++++++++++++++
 .../apache/bookkeeper/common/net/package-info.java |  22 +-
 .../bookkeeper/common/net/ServiceURITest.java      | 221 +++++++++++++++++++
 .../bookkeeper/stream/cli/StreamStorageCli.java    |  13 +-
 .../clients/TestStorageClientBuilder.java          |   4 +-
 .../clients/config/StorageClientSettings.java      |  40 +---
 .../clients/impl/internal/LocationClientImpl.java  |  24 +--
 .../resolver/SimpleStreamResolverFactory.java      |  90 --------
 .../bookkeeper/clients/utils/GrpcChannels.java     |  64 ++++++
 .../clients/config/TestStorageClientSettings.java  |  15 +-
 .../clients/grpc/GrpcClientTestBase.java           |   6 +-
 .../impl/internal/RootRangeClientImplTestBase.java |   7 +-
 .../impl/internal/TestLocationClientImpl.java      |   4 +-
 .../impl/internal/TestMetaRangeClientImpl.java     |   5 +-
 .../resolver/ServiceNameResolverProvider.java      | 164 ++++++++++++++
 ...leNameResolver.java => StaticNameResolver.java} |   4 +-
 .../common/reslover/TestSimpleNameResolver.java    |   6 +-
 .../org/apache/distributedlog/util/DLUtils.java    |  17 +-
 .../namespace/TestNamespaceBuilder.java            |   3 -
 .../bookkeeper/stream/cluster/StreamCluster.java   |  12 +-
 .../integration/stream/StreamClusterTestBase.java  |   7 +-
 21 files changed, 750 insertions(+), 213 deletions(-)

diff --git a/bookkeeper-common/src/main/java/org/apache/bookkeeper/common/net/ServiceURI.java b/bookkeeper-common/src/main/java/org/apache/bookkeeper/common/net/ServiceURI.java
new file mode 100644
index 0000000..289c3f3
--- /dev/null
+++ b/bookkeeper-common/src/main/java/org/apache/bookkeeper/common/net/ServiceURI.java
@@ -0,0 +1,235 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.bookkeeper.common.net;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.CharMatcher;
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import java.net.URI;
+import java.util.List;
+import lombok.AccessLevel;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import org.apache.bookkeeper.common.annotation.InterfaceAudience.Public;
+import org.apache.bookkeeper.common.annotation.InterfaceStability.Evolving;
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * ServiceURI represents service uri within bookkeeper cluster.
+ *
+ * <h3>Service URI syntax and components</h3>
+ *
+ * <p>At the highest level a service uri is a {@link java.net.URI} in string
+ * form has the syntax.
+ *
+ * <blockquote>
+ * [<i>service</i>[<i>service-specific-part</i>]<b>{@code :}</b>[<b>{@code //}</b><i>authority</i>][<i>path</i>]
+ * </blockquote>
+ *
+ * <p>where the characters <b>{@code :}</b> and <b>{@code /}</b> stand for themselves.
+ *
+ * <p>The service-specific-part of a service URI consists of the backend information used for services to use.
+ * It has the syntax as below:
+ *
+ * <blockquote>
+ * [({@code -}|{@code +})][<i>backend-part</i>]
+ * </blockquote>
+ *
+ * <p>where the characters <b>{@code -}</b> and <b>{@code +}</b> stand as a separator to separate service type
+ * from service backend information.
+ *
+ * <p>The authority component of a service URI has the same meaning as the authority component
+ * in a {@link java.net.URI}. If specified, it should be <i>server-based</i>. A server-based
+ * authority parses according to the familiar syntax
+ *
+ * <blockquote>
+ * [<i>user-info</i><b>{@code @}</b>]<i>host</i>[<b>{@code :}</b><i>port</i>]
+ * </blockquote>
+ *
+ * <p>where the characters <b>{@code @}</b> and <b>{@code :}</b> stand for themselves.
+ *
+ * <p>The path component of a service URI is itself said to be absolute. It typically means which path a service
+ * stores metadata or data.
+ *
+ * <p>All told, then, a service URI instance has the following components:
+ *
+ * <blockquote>
+ * <table summary="Describes the components of a service
+ * URI:service,service-specific-part,authority,user-info,host,port,path">
+ * <tr><td>service</td><td>{@code String}</td></tr>
+ * <tr><td>service-specific-part&nbsp;&nbsp;&nbsp;&nbsp;</td><td>{@code String}</td></tr>
+ * <tr><td>authority</td><td>{@code String}</td></tr>
+ * <tr><td>user-info</td><td>{@code String}</td></tr>
+ * <tr><td>host</td><td>{@code String}</td></tr>
+ * <tr><td>port</td><td>{@code int}</td></tr>
+ * <tr><td>path</td><td>{@code String}</td></tr>
+ * </table>
+ * </blockquote>
+ *
+ * <p>Some examples of service URIs are:
+ *
+ * <blockquote>
+ * {@code zk://localhost:2181/cluster1/ledgers} =&gt; ledger service uri using default ledger manager<br>
+ * {@code zk+hierarchical://localhost:2181/ledgers} =&gt; ledger service uri using hierarchical ledger manager<br>
+ * {@code etcd://localhost/ledgers} =&gt; ledger service uri using etcd as metadata store<br>
+ * {@code distributedlog://localhost:2181/distributedlog} =&gt; distributedlog namespace<br>
+ * {@code distributedlog-bk://localhost:2181/distributedlog} =&gt; distributedlog namespace with bk backend<br>
+ * {@code bk://bookkeeper-cluster/} =&gt; stream storage service uri <br>
+ * {@code host1:port,host2:port} =&gt; a list of hosts as bootstrap hosts to a stream storage cluster}
+ * </blockquote>
+ *
+ * @since 4.8.0
+ */
+@Public
+@Evolving
+@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
+@Getter
+@EqualsAndHashCode
+public class ServiceURI {
+
+    /**
+     * Service string for ledger service that uses zookeeper as metadata store.
+     */
+    public static final String SERVICE_ZK   = "zk";
+
+    /**
+     * Service string for dlog service.
+     */
+    public static final String SERVICE_DLOG = "distributedlog";
+
+    /**
+     * Service string for bookkeeper service.
+     */
+    public static final String SERVICE_BK = "bk";
+
+    private static final String SERVICE_SEP = "+";
+    private static final String SERVICE_DLOG_SEP = "-";
+
+    /**
+     * Create a service uri instance from a uri string.
+     *
+     * @param uriStr service uri string
+     * @return a service uri instance
+     * @throws NullPointerException if {@code uriStr} is null
+     * @throws IllegalArgumentException if the given string violates RFC&nbsp;2396
+     */
+    public static ServiceURI create(String uriStr) {
+        checkNotNull(uriStr, "service uri string is null");
+
+        // a service uri first should be a valid java.net.URI
+        URI uri = URI.create(uriStr);
+
+        return create(uri);
+    }
+
+    /**
+     * Create a service uri instance from a {@link URI} instance.
+     *
+     * @param uri {@link URI} instance
+     * @return a service uri instance
+     * @throws NullPointerException if {@code uriStr} is null
+     * @throws IllegalArgumentException if the given string violates RFC&nbsp;2396
+     */
+    public static ServiceURI create(URI uri) {
+        checkNotNull(uri, "service uri instance is null");
+
+        String serviceName = null;
+        String[] serviceInfos = new String[0];
+        String scheme = uri.getScheme();
+        if (null != scheme) {
+            scheme = scheme.toLowerCase();
+            final String serviceSep;
+            if (scheme.startsWith(SERVICE_DLOG)) {
+                serviceSep = SERVICE_DLOG_SEP;
+            } else {
+                serviceSep = SERVICE_SEP;
+            }
+            String[] schemeParts = StringUtils.split(scheme, serviceSep);
+            serviceName = schemeParts[0];
+            serviceInfos = new String[schemeParts.length - 1];
+            System.arraycopy(schemeParts, 1, serviceInfos, 0, serviceInfos.length);
+        }
+
+        String userAndHostInformation = uri.getAuthority();
+        checkArgument(!Strings.isNullOrEmpty(userAndHostInformation),
+            "authority component is missing in service uri : " + uri);
+
+        String serviceUser;
+        List<String> serviceHosts;
+        int atIndex = userAndHostInformation.indexOf('@');
+        Splitter splitter = Splitter.on(CharMatcher.anyOf(",;"));
+        if (atIndex > 0) {
+            serviceUser = userAndHostInformation.substring(0, atIndex);
+            serviceHosts = splitter.splitToList(userAndHostInformation.substring(atIndex + 1));
+        } else {
+            serviceUser = null;
+            serviceHosts = splitter.splitToList(userAndHostInformation);
+        }
+        serviceHosts.forEach(host -> validateHostName(host));
+
+        String servicePath = uri.getPath();
+        checkArgument(null != servicePath,
+            "service path component is missing in service uri : " + uri);
+
+        return new ServiceURI(
+            serviceName,
+            serviceInfos,
+            serviceUser,
+            serviceHosts.toArray(new String[serviceHosts.size()]),
+            servicePath,
+            uri);
+    }
+
+    private static void validateHostName(String hostname) {
+        String[] parts = hostname.split(":");
+        if (parts.length >= 3) {
+            throw new IllegalArgumentException("Invalid hostname : " + hostname);
+        } else if (parts.length == 2) {
+            try {
+                Integer.parseUnsignedInt(parts[1]);
+            } catch (NumberFormatException nfe) {
+                throw new IllegalArgumentException("Invalid hostname : " + hostname);
+            }
+        }
+
+    }
+
+    private final String serviceName;
+    private final String[] serviceInfos;
+    private final String serviceUser;
+    private final String[] serviceHosts;
+    private final String servicePath;
+    private final URI uri;
+
+    @SuppressFBWarnings("EI_EXPOSE_REP")
+    public String[] getServiceInfos() {
+        return serviceInfos;
+    }
+
+    @SuppressFBWarnings("EI_EXPOSE_REP")
+    public String[] getServiceHosts() {
+        return serviceHosts;
+    }
+
+}
diff --git a/stream/common/src/main/java/org/apache/bookkeeper/common/resolver/AbstractNameResolverFactory.java b/bookkeeper-common/src/main/java/org/apache/bookkeeper/common/net/package-info.java
similarity index 57%
rename from stream/common/src/main/java/org/apache/bookkeeper/common/resolver/AbstractNameResolverFactory.java
rename to bookkeeper-common/src/main/java/org/apache/bookkeeper/common/net/package-info.java
index 725b5f7..cb0b13a 100644
--- a/stream/common/src/main/java/org/apache/bookkeeper/common/resolver/AbstractNameResolverFactory.java
+++ b/bookkeeper-common/src/main/java/org/apache/bookkeeper/common/net/package-info.java
@@ -7,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -16,23 +16,7 @@
  * limitations under the License.
  */
 
-package org.apache.bookkeeper.common.resolver;
-
-import io.grpc.NameResolver;
-
 /**
- * The abstract bookkeeper name resolver factory.
- *
- * <p>The name resolver is responsible for creating specific name resolver
- * which provides addresses for {@link io.grpc.LoadBalancer}.
+ * Classes for resolving service uris in bookkeeper.
  */
-public abstract class AbstractNameResolverFactory extends NameResolver.Factory {
-
-    /**
-     * Gets name of the name resolver factory.
-     *
-     * @return name of the name resolver factory.
-     */
-    public abstract String name();
-
-}
+package org.apache.bookkeeper.common.net;
\ No newline at end of file
diff --git a/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/net/ServiceURITest.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/net/ServiceURITest.java
new file mode 100644
index 0000000..9982c43
--- /dev/null
+++ b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/net/ServiceURITest.java
@@ -0,0 +1,221 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.bookkeeper.common.net;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.net.URI;
+import org.junit.Test;
+
+/**
+ * Unit test {@link ServiceURI}.
+ */
+public class ServiceURITest {
+
+    private static void assertServiceUri(
+        String serviceUri,
+        String expectedServiceName,
+        String[] expectedServiceInfo,
+        String expectedServiceUser,
+        String[] expectedServiceHosts,
+        String expectedServicePath) {
+
+        ServiceURI serviceURI = ServiceURI.create(serviceUri);
+
+        assertEquals(expectedServiceName, serviceURI.getServiceName());
+        assertArrayEquals(expectedServiceInfo, serviceURI.getServiceInfos());
+        assertEquals(expectedServiceUser, serviceURI.getServiceUser());
+        assertArrayEquals(expectedServiceHosts, serviceURI.getServiceHosts());
+        assertEquals(expectedServicePath, serviceURI.getServicePath());
+    }
+
+    @Test
+    public void testInvalidServiceUris() {
+        String[] uris = new String[] {
+            "://localhost:2181/path/to/namespace",          // missing scheme
+            "bk:///path/to/namespace",                      // missing authority
+            "bk://localhost:2181:3181/path/to/namespace",   // invalid hostname pair
+            "bk://localhost:xyz/path/to/namespace",         // invalid port
+            "bk://localhost:-2181/path/to/namespace",       // negative port
+        };
+
+        for (String uri : uris) {
+            testInvalidServiceUri(uri);
+        }
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testNullServiceUriString() {
+        ServiceURI.create((String) null);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testNullServiceUriInstance() {
+        ServiceURI.create((URI) null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testEmptyServiceUriString() {
+        ServiceURI.create("");
+    }
+
+    private void testInvalidServiceUri(String serviceUri) {
+        try {
+            ServiceURI.create(serviceUri);
+            fail("Should fail to parse service uri : " + serviceUri);
+        } catch (IllegalArgumentException iae) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testMissingServiceName() {
+        String serviceUri = "//localhost:2181/path/to/namespace";
+        assertServiceUri(
+            serviceUri,
+            null, new String[0], null, new String[] { "localhost:2181" }, "/path/to/namespace");
+    }
+
+    @Test
+    public void testEmptyPath() {
+        String serviceUri = "bk://localhost:2181";
+        assertServiceUri(
+            serviceUri,
+            "bk", new String[0], null, new String[] { "localhost:2181" }, "");
+    }
+
+    @Test
+    public void testRootPath() {
+        String serviceUri = "bk://localhost:2181/";
+        assertServiceUri(
+            serviceUri,
+            "bk", new String[0], null, new String[] { "localhost:2181" }, "/");
+    }
+
+    @Test
+    public void testUserInfo() {
+        String serviceUri = "bk://bookkeeper@localhost:2181/path/to/namespace";
+        assertServiceUri(
+            serviceUri,
+            "bk",
+            new String[0],
+            "bookkeeper",
+            new String[] { "localhost:2181" },
+            "/path/to/namespace");
+    }
+
+    @Test
+    public void testMultipleHostsSemiColon() {
+        String serviceUri = "bk://host1:2181;host2:2181;host3:2181/path/to/namespace";
+        assertServiceUri(
+            serviceUri,
+            "bk",
+            new String[0],
+            null,
+            new String[] { "host1:2181", "host2:2181", "host3:2181" },
+            "/path/to/namespace");
+    }
+
+    @Test
+    public void testMultipleHostsComma() {
+        String serviceUri = "bk://host1:2181,host2:2181,host3:2181/path/to/namespace";
+        assertServiceUri(
+            serviceUri,
+            "bk",
+            new String[0],
+            null,
+            new String[] { "host1:2181", "host2:2181", "host3:2181" },
+            "/path/to/namespace");
+    }
+
+    @Test
+    public void testMultipleHostsWithoutPorts() {
+        String serviceUri = "bk://host1,host2,host3/path/to/namespace";
+        assertServiceUri(
+            serviceUri,
+            "bk",
+            new String[0],
+            null,
+            new String[] { "host1", "host2", "host3" },
+            "/path/to/namespace");
+    }
+
+    @Test
+    public void testMultipleHostsMixed() {
+        String serviceUri = "bk://host1:2181,host2,host3:2181/path/to/namespace";
+        assertServiceUri(
+            serviceUri,
+            "bk",
+            new String[0],
+            null,
+            new String[] { "host1:2181", "host2", "host3:2181" },
+            "/path/to/namespace");
+    }
+
+    @Test
+    public void testUserInfoWithMultipleHosts() {
+        String serviceUri = "bk://bookkeeper@host1:2181;host2:2181;host3:2181/path/to/namespace";
+        assertServiceUri(
+            serviceUri,
+            "bk",
+            new String[0],
+            "bookkeeper",
+            new String[] { "host1:2181", "host2:2181", "host3:2181" },
+            "/path/to/namespace");
+    }
+
+    @Test
+    public void testServiceInfoPlus() {
+        String serviceUri = "bk+ssl://host:2181/path/to/namespace";
+        assertServiceUri(
+            serviceUri,
+            "bk",
+            new String[] { "ssl" },
+            null,
+            new String[] { "host:2181" },
+            "/path/to/namespace");
+    }
+
+    @Test
+    public void testServiceInfoMinus() {
+        String serviceUri = "bk-ssl://host:2181/path/to/namespace";
+        assertServiceUri(
+            serviceUri,
+            "bk-ssl",
+            new String[0],
+            null,
+            new String[] { "host:2181" },
+            "/path/to/namespace");
+    }
+
+    @Test
+    public void testServiceInfoDlogMinus() {
+        String serviceUri = "distributedlog-bk://host:2181/path/to/namespace";
+        assertServiceUri(
+            serviceUri,
+            "distributedlog",
+            new String[] { "bk" },
+            null,
+            new String[] { "host:2181" },
+            "/path/to/namespace");
+    }
+
+}
diff --git a/stream/cli/src/main/java/org/apache/bookkeeper/stream/cli/StreamStorageCli.java b/stream/cli/src/main/java/org/apache/bookkeeper/stream/cli/StreamStorageCli.java
index f0e7974..b1ac239 100644
--- a/stream/cli/src/main/java/org/apache/bookkeeper/stream/cli/StreamStorageCli.java
+++ b/stream/cli/src/main/java/org/apache/bookkeeper/stream/cli/StreamStorageCli.java
@@ -28,12 +28,10 @@ import lombok.AccessLevel;
 import lombok.Getter;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.bookkeeper.clients.config.StorageClientSettings;
-import org.apache.bookkeeper.clients.utils.NetUtils;
 import org.apache.bookkeeper.stream.cli.commands.CmdBase;
 import org.apache.bookkeeper.stream.cli.commands.CmdNamespace;
 import org.apache.bookkeeper.stream.cli.commands.CmdStream;
 import org.apache.bookkeeper.stream.cli.commands.CmdTable;
-import org.apache.bookkeeper.stream.proto.common.Endpoint;
 
 /**
  * Bookie Shell.
@@ -83,8 +81,8 @@ public class StreamStorageCli {
     @Getter(AccessLevel.PACKAGE)
     static class ShellArguments {
 
-        @Parameter(names = { "-s", "--server" }, description = "A storage server address")
-        private String endpoint = null;
+        @Parameter(names = { "-u", "--server-uri" }, description = "The bookkeeper service uri")
+        private String serviceUri = "bk://localhost:4181";
 
         @Parameter(names = { "-n", "--namespace" }, description = "Namespace")
         private String namespace = "default";
@@ -155,16 +153,15 @@ public class StreamStorageCli {
             return false;
         }
 
-        if (null == shellArgs.endpoint) {
+        if (null == shellArgs.serviceUri) {
             System.err.println("No endpoint is provided");
             commander.usage();
             return false;
         }
 
-        Endpoint endpoint = NetUtils.parseEndpoint(shellArgs.endpoint);
-        settingsBuilder.addEndpoints(endpoint);
+        settingsBuilder.serviceUri(shellArgs.serviceUri);
 
-        log.info("connecting to storage service = {}", endpoint);
+        log.info("connecting to storage service = {}", shellArgs.serviceUri);
 
         if (cmdPos == args.length) {
             commander.usage();
diff --git a/stream/clients/java/all/src/test/java/org/apache/bookkeeper/clients/TestStorageClientBuilder.java b/stream/clients/java/all/src/test/java/org/apache/bookkeeper/clients/TestStorageClientBuilder.java
index c80010a..39bd14a 100644
--- a/stream/clients/java/all/src/test/java/org/apache/bookkeeper/clients/TestStorageClientBuilder.java
+++ b/stream/clients/java/all/src/test/java/org/apache/bookkeeper/clients/TestStorageClientBuilder.java
@@ -47,7 +47,9 @@ public class TestStorageClientBuilder {
     @Test(expected = IllegalArgumentException.class)
     public void testBuildClientInvalidNamespaceName() {
         StorageClientBuilder.newBuilder()
-            .withSettings(mock(StorageClientSettings.class))
+            .withSettings(StorageClientSettings.newBuilder()
+                .serviceUri("bk://localhost:4181")
+                .build())
             .withNamespace("invalid-namespace")
             .build();
     }
diff --git a/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/config/StorageClientSettings.java b/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/config/StorageClientSettings.java
index 87768fa..9a0fc6d 100644
--- a/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/config/StorageClientSettings.java
+++ b/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/config/StorageClientSettings.java
@@ -18,16 +18,11 @@
 
 package org.apache.bookkeeper.clients.config;
 
-import static com.google.common.base.Preconditions.checkArgument;
-
-import io.grpc.ManagedChannelBuilder;
-import io.grpc.NameResolver;
-import java.util.List;
 import java.util.Optional;
 import org.apache.bookkeeper.clients.resolver.EndpointResolver;
 import org.apache.bookkeeper.clients.utils.ClientConstants;
+import org.apache.bookkeeper.common.net.ServiceURI;
 import org.apache.bookkeeper.common.util.Backoff;
-import org.apache.bookkeeper.stream.proto.common.Endpoint;
 import org.inferred.freebuilder.FreeBuilder;
 
 /**
@@ -44,18 +39,11 @@ public interface StorageClientSettings {
     int numWorkerThreads();
 
     /**
-     * Returns the name resolver factory used by zstream client.
-     *
-     * @return name resolver factory.
-     */
-    Optional<NameResolver.Factory> nameResolverFactory();
-
-    /**
-     * Returns the endpoints used by the client builder.
+     * Returns the service uri that storage client should talk to.
      *
-     * @return the list of endpoints.
+     * @return service uri
      */
-    List<Endpoint> endpoints();
+    String serviceUri();
 
     /**
      * Return the endpoint resolver for resolving individual endpoints.
@@ -67,13 +55,6 @@ public interface StorageClientSettings {
     EndpointResolver endpointResolver();
 
     /**
-     * Returns the builder to create the managed channel.
-     *
-     * @return
-     */
-    Optional<ManagedChannelBuilder> managedChannelBuilder();
-
-    /**
      * Use of a plaintext connection to the server. By default a secure connection mechanism
      * such as TLS will be used.
      *
@@ -114,14 +95,13 @@ public interface StorageClientSettings {
 
         @Override
         public StorageClientSettings build() {
-            checkArgument(
-                nameResolverFactory().isPresent()
-                    || !endpoints().isEmpty()
-                    || managedChannelBuilder().isPresent(),
-                "No name resolver or endpoints or channel builder provided");
-            return super.build();
-        }
+            StorageClientSettings settings = super.build();
+
+            // create a service uri to ensure the service uri is valid
+            ServiceURI.create(serviceUri());
 
+            return settings;
+        }
     }
 
     static Builder newBuilder() {
diff --git a/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/internal/LocationClientImpl.java b/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/internal/LocationClientImpl.java
index db1c656..8b589c3 100644
--- a/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/internal/LocationClientImpl.java
+++ b/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/internal/LocationClientImpl.java
@@ -24,8 +24,6 @@ import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createGetSto
 
 import com.google.common.annotations.VisibleForTesting;
 import io.grpc.ManagedChannel;
-import io.grpc.ManagedChannelBuilder;
-import io.grpc.NameResolver;
 import io.grpc.Status;
 import io.grpc.StatusException;
 import io.grpc.StatusRuntimeException;
@@ -36,8 +34,8 @@ import java.util.function.Predicate;
 import java.util.stream.Stream;
 import org.apache.bookkeeper.clients.config.StorageClientSettings;
 import org.apache.bookkeeper.clients.impl.internal.api.LocationClient;
-import org.apache.bookkeeper.clients.resolver.SimpleStreamResolverFactory;
 import org.apache.bookkeeper.clients.utils.ClientConstants;
+import org.apache.bookkeeper.clients.utils.GrpcChannels;
 import org.apache.bookkeeper.clients.utils.GrpcUtils;
 import org.apache.bookkeeper.common.util.Backoff;
 import org.apache.bookkeeper.common.util.OrderedScheduler;
@@ -63,28 +61,14 @@ public class LocationClientImpl implements LocationClient {
                               OrderedScheduler scheduler) {
         this.settings = settings;
         this.scheduler = scheduler;
-        ManagedChannelBuilder builder = settings.managedChannelBuilder().orElse(
-            ManagedChannelBuilder
-                .forTarget("stream")
-                .nameResolverFactory(getResolver(settings))
-        );
-        if (settings.usePlaintext()) {
-            builder = builder.usePlaintext(true);
-        }
-        this.channel = builder.build();
+        this.channel = GrpcChannels.createChannelBuilder(
+            settings.serviceUri(), settings
+        ).build();
         this.locationService = GrpcUtils.configureGrpcStub(
             StorageContainerServiceGrpc.newFutureStub(channel),
             Optional.empty());
     }
 
-    private NameResolver.Factory getResolver(StorageClientSettings settings) {
-        if (settings.nameResolverFactory().isPresent()) {
-            return settings.nameResolverFactory().get();
-        } else {
-            return SimpleStreamResolverFactory.of(settings.endpoints());
-        }
-    }
-
     private Stream<Long> getDefaultBackoffs() {
         return Backoff.exponential(
             ClientConstants.DEFAULT_BACKOFF_START_MS,
diff --git a/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/resolver/SimpleStreamResolverFactory.java b/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/resolver/SimpleStreamResolverFactory.java
deleted file mode 100644
index 512ee06..0000000
--- a/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/resolver/SimpleStreamResolverFactory.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.bookkeeper.clients.resolver;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.base.Function;
-import com.google.common.base.Objects;
-import com.google.common.collect.Lists;
-import io.grpc.Attributes;
-import io.grpc.NameResolver;
-import java.net.URI;
-import java.util.List;
-import javax.annotation.Nullable;
-import org.apache.bookkeeper.clients.utils.ClientResources;
-import org.apache.bookkeeper.common.resolver.AbstractNameResolverFactory;
-import org.apache.bookkeeper.common.resolver.SimpleNameResolver;
-import org.apache.bookkeeper.stream.proto.common.Endpoint;
-
-/**
- * A simple resolver factory that creates simple name resolver.
- */
-public class SimpleStreamResolverFactory extends AbstractNameResolverFactory {
-
-    private static final String SCHEME = "stream";
-    private static final String NAME = "simple";
-
-    public static final SimpleStreamResolverFactory of(List<Endpoint> endpoints) {
-        return new SimpleStreamResolverFactory(endpoints);
-    }
-
-    public static final SimpleStreamResolverFactory of(Endpoint... endpoints) {
-        return new SimpleStreamResolverFactory(Lists.newArrayList(endpoints));
-    }
-
-    private final List<URI> endpointURIs;
-
-    private SimpleStreamResolverFactory(List<Endpoint> endpoints) {
-        this.endpointURIs = Lists.transform(
-            endpoints,
-            new Function<Endpoint, URI>() {
-                @Override
-                public URI apply(Endpoint endpoint) {
-                    return URI.create(SCHEME + "://" + endpoint.getHostname() + ":" + endpoint.getPort());
-                }
-            }
-        );
-    }
-
-    @Override
-    public String name() {
-        return NAME;
-    }
-
-    @Nullable
-    @Override
-    public NameResolver newNameResolver(URI targetUri, Attributes params) {
-        if (!Objects.equal(SCHEME, targetUri.getScheme())) {
-            return null;
-        }
-        String targetPath = checkNotNull(targetUri.getPath());
-        checkArgument(targetPath.startsWith("/"),
-            "the path component (%s) of the target (%s) must start with '/'",
-            targetPath, targetUri);
-        String name = targetPath.substring(1);
-        return new SimpleNameResolver(name, ClientResources.shared().executor(), this.endpointURIs);
-    }
-
-    @Override
-    public String getDefaultScheme() {
-        return SCHEME;
-    }
-}
diff --git a/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/utils/GrpcChannels.java b/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/utils/GrpcChannels.java
new file mode 100644
index 0000000..8588359
--- /dev/null
+++ b/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/utils/GrpcChannels.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.bookkeeper.clients.utils;
+
+import io.grpc.ManagedChannelBuilder;
+import io.grpc.inprocess.InProcessChannelBuilder;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.bookkeeper.clients.config.StorageClientSettings;
+import org.apache.bookkeeper.common.net.ServiceURI;
+import org.apache.bookkeeper.common.resolver.ServiceNameResolverProvider;
+
+/**
+ * Utils to create grpc channels.
+ */
+@Slf4j
+public final class GrpcChannels {
+
+    private static final String BACKEND_INPROCESS = "inprocess";
+
+    private GrpcChannels() {}
+
+    /**
+     * Create a channel builder from <tt>serviceUri</tt> with client <tt>settings</tt>.
+     *
+     * @param serviceUri service uri
+     * @param settings client settings
+     * @return managed channel builder
+     */
+    public static ManagedChannelBuilder createChannelBuilder(String serviceUri,
+                                                             StorageClientSettings settings) {
+        ServiceURI uri = ServiceURI.create(serviceUri);
+
+        ManagedChannelBuilder builder;
+        if (uri.getServiceInfos().length > 0 && uri.getServiceInfos()[0].equals(BACKEND_INPROCESS)) {
+            // this is an inprocess service, so build an inprocess channel.
+            String serviceName = uri.getServiceHosts()[0];
+            builder = InProcessChannelBuilder.forName(serviceName).directExecutor();
+        } else {
+            builder = ManagedChannelBuilder.forTarget(serviceUri)
+                .nameResolverFactory(new ServiceNameResolverProvider().toFactory());
+        }
+        if (settings.usePlaintext()) {
+            builder = builder.usePlaintext();
+        }
+        return builder;
+    }
+
+}
diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/config/TestStorageClientSettings.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/config/TestStorageClientSettings.java
index ae08c83..a4e4294 100644
--- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/config/TestStorageClientSettings.java
+++ b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/config/TestStorageClientSettings.java
@@ -23,9 +23,6 @@ import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import com.google.common.collect.Lists;
-import java.util.List;
-import org.apache.bookkeeper.stream.proto.common.Endpoint;
 import org.junit.Test;
 
 /**
@@ -35,14 +32,10 @@ public class TestStorageClientSettings {
 
     @Test
     public void testDefault() {
-        List<Endpoint> endpoints = Lists.newArrayList(
-            Endpoint.newBuilder()
-                .setHostname("127.0.0.1")
-                .setPort(80)
-                .build());
         StorageClientSettings settings = StorageClientSettings.newBuilder()
-            .addAllEndpoints(endpoints)
+            .serviceUri("bk://127.0.0.1:4181/")
             .build();
+        assertEquals("bk://127.0.0.1:4181/", settings.serviceUri());
         assertEquals(Runtime.getRuntime().availableProcessors(), settings.numWorkerThreads());
         assertTrue(settings.usePlaintext());
         assertFalse(settings.clientName().isPresent());
@@ -53,8 +46,8 @@ public class TestStorageClientSettings {
         try {
             StorageClientSettings.newBuilder().build();
             fail("Should fail with missing endpoints");
-        } catch (IllegalArgumentException iae) {
-            assertEquals("No name resolver or endpoints or channel builder provided", iae.getMessage());
+        } catch (IllegalStateException iae) {
+            assertEquals("Not set: [serviceUri]", iae.getMessage());
         }
     }
 
diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/grpc/GrpcClientTestBase.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/grpc/GrpcClientTestBase.java
index 9088fde..f90a9aa 100644
--- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/grpc/GrpcClientTestBase.java
+++ b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/grpc/GrpcClientTestBase.java
@@ -50,7 +50,7 @@ public abstract class GrpcClientTestBase {
         .setPort(4181)
         .build();
 
-    protected String serverName = "fake server for " + getClass();
+    protected String serverName;
     protected final MutableHandlerRegistry serviceRegistry = new MutableHandlerRegistry();
     protected Server fakeServer;
     protected OrderedScheduler scheduler;
@@ -61,6 +61,7 @@ public abstract class GrpcClientTestBase {
 
     @Before
     public void setUp() throws Exception {
+        serverName = "fake-server";
         fakeServer = InProcessServerBuilder
             .forName(serverName)
             .fallbackHandlerRegistry(serviceRegistry)
@@ -72,8 +73,7 @@ public abstract class GrpcClientTestBase {
             .numThreads(Runtime.getRuntime().availableProcessors())
             .build();
         settings = StorageClientSettings.newBuilder()
-            .managedChannelBuilder(InProcessChannelBuilder.forName(serverName).directExecutor())
-            .usePlaintext(true)
+            .serviceUri("bk+inprocess://" + serverName)
             .build();
         serverManager = new StorageServerClientManagerImpl(
             settings,
diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/RootRangeClientImplTestBase.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/RootRangeClientImplTestBase.java
index a962a21..c61052c 100644
--- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/RootRangeClientImplTestBase.java
+++ b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/RootRangeClientImplTestBase.java
@@ -27,6 +27,7 @@ import io.grpc.inprocess.InProcessChannelBuilder;
 import java.io.IOException;
 import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
+import lombok.Cleanup;
 import org.apache.bookkeeper.clients.exceptions.ClientException;
 import org.apache.bookkeeper.clients.exceptions.InvalidNamespaceNameException;
 import org.apache.bookkeeper.clients.exceptions.NamespaceExistsException;
@@ -118,7 +119,7 @@ public abstract class RootRangeClientImplTestBase extends GrpcClientTestBase {
 
         RootRangeServiceImplBase rootRangeService = createRootRangeServiceForSuccess();
         serviceRegistry.addService(rootRangeService.bindService());
-        StorageServerChannel rsChannel = new StorageServerChannel(
+        @Cleanup StorageServerChannel rsChannel = new StorageServerChannel(
             InProcessChannelBuilder.forName(serverName).directExecutor().build(),
             Optional.empty());
         serviceFuture.complete(rsChannel);
@@ -138,7 +139,7 @@ public abstract class RootRangeClientImplTestBase extends GrpcClientTestBase {
 
         RootRangeServiceImplBase rootRangeService = createRootRangeServiceForRequestFailure();
         serviceRegistry.addService(rootRangeService.bindService());
-        StorageServerChannel rsChannel = new StorageServerChannel(
+        @Cleanup StorageServerChannel rsChannel = new StorageServerChannel(
             InProcessChannelBuilder.forName(serverName).directExecutor().build(),
             Optional.empty());
         serviceFuture.complete(rsChannel);
@@ -158,7 +159,7 @@ public abstract class RootRangeClientImplTestBase extends GrpcClientTestBase {
 
         RootRangeServiceImplBase rootRangeService = createRootRangeServiceForRpcFailure();
         serviceRegistry.addService(rootRangeService.bindService());
-        StorageServerChannel rsChannel = new StorageServerChannel(
+        @Cleanup StorageServerChannel rsChannel = new StorageServerChannel(
             InProcessChannelBuilder.forName(serverName).directExecutor().build(),
             Optional.empty());
         serviceFuture.complete(rsChannel);
diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestLocationClientImpl.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestLocationClientImpl.java
index c2d4fc2..665b8ac 100644
--- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestLocationClientImpl.java
+++ b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestLocationClientImpl.java
@@ -30,7 +30,6 @@ import io.grpc.ServerServiceDefinition;
 import io.grpc.Status;
 import io.grpc.StatusException;
 import io.grpc.StatusRuntimeException;
-import io.grpc.inprocess.InProcessChannelBuilder;
 import io.grpc.stub.StreamObserver;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
@@ -129,8 +128,7 @@ public class TestLocationClientImpl extends GrpcClientTestBase {
     protected void doSetup() throws Exception {
         StorageClientSettings settings =
             StorageClientSettings.newBuilder()
-                .managedChannelBuilder(InProcessChannelBuilder.forName(serverName).directExecutor())
-                .usePlaintext(true)
+                .serviceUri("bk+inprocess://" + serverName)
                 .build();
         locationClient = new LocationClientImpl(settings, scheduler);
         locationServiceDefinition = locationService.bindService();
diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestMetaRangeClientImpl.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestMetaRangeClientImpl.java
index 9716162..985b955 100644
--- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestMetaRangeClientImpl.java
+++ b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestMetaRangeClientImpl.java
@@ -34,6 +34,7 @@ import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
+import lombok.Cleanup;
 import org.apache.bookkeeper.clients.grpc.GrpcClientTestBase;
 import org.apache.bookkeeper.clients.impl.channel.StorageServerChannel;
 import org.apache.bookkeeper.clients.impl.channel.StorageServerChannelManager;
@@ -145,7 +146,7 @@ public class TestMetaRangeClientImpl extends GrpcClientTestBase {
         };
         serviceRegistry.addService(metaRangeService.bindService());
 
-        StorageServerChannel rsChannel = new StorageServerChannel(
+        @Cleanup StorageServerChannel rsChannel = new StorageServerChannel(
             InProcessChannelBuilder.forName(serverName).directExecutor().build(),
             Optional.empty());
         serviceFuture.complete(rsChannel);
@@ -169,7 +170,7 @@ public class TestMetaRangeClientImpl extends GrpcClientTestBase {
         };
         serviceRegistry.addService(metaRangeService.bindService());
 
-        StorageServerChannel rsChannel = new StorageServerChannel(
+        @Cleanup StorageServerChannel rsChannel = new StorageServerChannel(
             InProcessChannelBuilder.forName(serverName).directExecutor().build(),
             Optional.empty());
         serviceFuture.complete(rsChannel);
diff --git a/stream/common/src/main/java/org/apache/bookkeeper/common/resolver/ServiceNameResolverProvider.java b/stream/common/src/main/java/org/apache/bookkeeper/common/resolver/ServiceNameResolverProvider.java
new file mode 100644
index 0000000..9e11adf
--- /dev/null
+++ b/stream/common/src/main/java/org/apache/bookkeeper/common/resolver/ServiceNameResolverProvider.java
@@ -0,0 +1,164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.bookkeeper.common.resolver;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+import io.grpc.Attributes;
+import io.grpc.NameResolver;
+import io.grpc.NameResolverProvider;
+import io.grpc.internal.DnsNameResolverProvider;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import javax.annotation.Nullable;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.bookkeeper.common.net.ServiceURI;
+import org.apache.bookkeeper.common.util.SharedResourceManager.Resource;
+
+/**
+ * An implementation of {@link NameResolverProvider} that provides {@link NameResolver}s
+ * to resolve {@link org.apache.bookkeeper.common.net.ServiceURI}.
+ */
+@Slf4j
+public final class ServiceNameResolverProvider extends NameResolverProvider {
+
+    private final DnsNameResolverProvider dnsProvider;
+    private final Resource<ExecutorService> executorResource;
+
+    public ServiceNameResolverProvider() {
+        this.dnsProvider = new DnsNameResolverProvider();
+        this.executorResource = new Resource<ExecutorService>() {
+            @Override
+            public ExecutorService create() {
+                return Executors.newSingleThreadScheduledExecutor();
+            }
+
+            @Override
+            public void close(ExecutorService instance) {
+                instance.shutdown();
+            }
+        };
+    }
+
+    @Override
+    protected boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    protected int priority() {
+        return 10;
+    }
+
+    @Nullable
+    @Override
+    public NameResolver newNameResolver(URI targetUri, Attributes params) {
+        ServiceURI serviceURI;
+        try {
+            serviceURI = ServiceURI.create(targetUri);
+        } catch (NullPointerException | IllegalArgumentException e) {
+            // invalid uri here, so return null to allow grpc to use other name resolvers
+            log.info("ServiceNameResolverProvider doesn't know how to resolve {} : cause {}",
+                targetUri, e.getMessage());
+            return null;
+        }
+
+        if (null == serviceURI.getServiceName()
+            || ServiceURI.SERVICE_BK.equals(serviceURI.getServiceName())) {
+
+            String[] hosts = serviceURI.getServiceHosts();
+            if (hosts.length == 0) {
+                // no host is find, so return null to let grpc choose other resolver.
+                return null;
+            } else if (hosts.length == 1) {
+                // create a dns name resolver
+                URI dnsUri = URI.create("dns:///" + hosts[0]);
+                return dnsProvider.newNameResolver(dnsUri, params);
+            } else {
+                // create a static resolver taking the list of servers.
+                List<String> hostList = new ArrayList<>();
+                for (String host : hosts) {
+                    hostList.add(host);
+                }
+                List<URI> hostUris = Lists.transform(
+                    hostList,
+                    new Function<String, URI>() {
+                        @Nullable
+                        @Override
+                        public URI apply(@Nullable String host) {
+                            return URI.create("//" + host);
+                        }
+                    }
+                );
+
+                return new StaticNameResolver(
+                    "static",
+                    executorResource,
+                    hostUris);
+            }
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public String getDefaultScheme() {
+        return ServiceURI.SERVICE_BK;
+    }
+
+    public NameResolver.Factory toFactory() {
+        return new NameResolverFactory(Lists.newArrayList(this));
+    }
+
+    private static class NameResolverFactory extends NameResolver.Factory {
+        private final List<NameResolverProvider> providers;
+
+        public NameResolverFactory(List<NameResolverProvider> providers) {
+            this.providers = providers;
+        }
+
+        @Override
+        public NameResolver newNameResolver(URI targetUri, Attributes params) {
+            checkForProviders();
+            for (NameResolverProvider provider : providers) {
+                NameResolver resolver = provider.newNameResolver(targetUri, params);
+                if (resolver != null) {
+                    return resolver;
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public String getDefaultScheme() {
+            checkForProviders();
+            return providers.get(0).getDefaultScheme();
+        }
+
+        private void checkForProviders() {
+            checkState(!providers.isEmpty(),
+                "No NameResolverProviders found. Please check your configuration");
+        }
+    }
+}
diff --git a/stream/common/src/main/java/org/apache/bookkeeper/common/resolver/SimpleNameResolver.java b/stream/common/src/main/java/org/apache/bookkeeper/common/resolver/StaticNameResolver.java
similarity index 94%
rename from stream/common/src/main/java/org/apache/bookkeeper/common/resolver/SimpleNameResolver.java
rename to stream/common/src/main/java/org/apache/bookkeeper/common/resolver/StaticNameResolver.java
index 7ff4e89..3f24ab9 100644
--- a/stream/common/src/main/java/org/apache/bookkeeper/common/resolver/SimpleNameResolver.java
+++ b/stream/common/src/main/java/org/apache/bookkeeper/common/resolver/StaticNameResolver.java
@@ -32,11 +32,11 @@ import org.apache.bookkeeper.common.util.SharedResourceManager.Resource;
 /**
  * A simple name resolver that returns pre-configured host addresses.
  */
-public class SimpleNameResolver extends AbstractNameResolver {
+public class StaticNameResolver extends AbstractNameResolver {
 
     private final List<EquivalentAddressGroup> servers;
 
-    public SimpleNameResolver(String name,
+    public StaticNameResolver(String name,
                               Resource<ExecutorService> executorResource,
                               List<URI> endpoints) {
         super(name, executorResource);
diff --git a/stream/common/src/test/java/org/apache/bookkeeper/common/reslover/TestSimpleNameResolver.java b/stream/common/src/test/java/org/apache/bookkeeper/common/reslover/TestSimpleNameResolver.java
index 58a0971..a781486 100644
--- a/stream/common/src/test/java/org/apache/bookkeeper/common/reslover/TestSimpleNameResolver.java
+++ b/stream/common/src/test/java/org/apache/bookkeeper/common/reslover/TestSimpleNameResolver.java
@@ -28,12 +28,12 @@ import java.net.InetSocketAddress;
 import java.net.URI;
 import java.util.List;
 import java.util.stream.Collectors;
-import org.apache.bookkeeper.common.resolver.SimpleNameResolver;
+import org.apache.bookkeeper.common.resolver.StaticNameResolver;
 import org.apache.bookkeeper.common.util.SharedResourceManager.Resource;
 import org.junit.Test;
 
 /**
- * Unit test of {@link SimpleNameResolver}.
+ * Unit test of {@link StaticNameResolver}.
  */
 public class TestSimpleNameResolver {
 
@@ -61,7 +61,7 @@ public class TestSimpleNameResolver {
             .collect(Collectors.toList());
 
         @SuppressWarnings("unchecked") // for the mock
-            SimpleNameResolver nameResolver = new SimpleNameResolver(
+            StaticNameResolver nameResolver = new StaticNameResolver(
             "test-name-resolver",
             mock(Resource.class),
             uris);
diff --git a/stream/distributedlog/core/src/main/java/org/apache/distributedlog/util/DLUtils.java b/stream/distributedlog/core/src/main/java/org/apache/distributedlog/util/DLUtils.java
index c89db47..635f86f 100644
--- a/stream/distributedlog/core/src/main/java/org/apache/distributedlog/util/DLUtils.java
+++ b/stream/distributedlog/core/src/main/java/org/apache/distributedlog/util/DLUtils.java
@@ -26,16 +26,12 @@ import java.net.InetAddress;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.List;
-import org.apache.commons.lang.StringUtils;
+import org.apache.bookkeeper.common.net.ServiceURI;
 import org.apache.distributedlog.DistributedLogConstants;
 import org.apache.distributedlog.LogSegmentMetadata;
 import org.apache.distributedlog.exceptions.InvalidStreamNameException;
 import org.apache.distributedlog.exceptions.UnexpectedException;
 
-
-
-
-
 /**
  * Utilities about DL implementations like uri, log segments, metadata serialization and deserialization.
  */
@@ -228,17 +224,14 @@ public class DLUtils {
      * @return the normalized uri
      */
     public static URI normalizeURI(URI uri) {
-        checkNotNull(uri, "DistributedLog uri is null");
-        String scheme = uri.getScheme();
-        checkNotNull(scheme, "Invalid distributedlog uri : " + uri);
-        scheme = scheme.toLowerCase();
-        String[] schemeParts = StringUtils.split(scheme, '-');
-        checkArgument(Objects.equal(DistributedLogConstants.SCHEME_PREFIX, schemeParts[0].toLowerCase()),
+        ServiceURI serviceURI = ServiceURI.create(uri);
+        checkNotNull(serviceURI.getServiceName(), "Invalid distributedlog uri : " + uri);
+        checkArgument(Objects.equal(DistributedLogConstants.SCHEME_PREFIX, serviceURI.getServiceName()),
                 "Unknown distributedlog scheme found : " + uri);
         URI normalizedUri;
         try {
             normalizedUri = new URI(
-                    schemeParts[0],     // remove backend info
+                    serviceURI.getServiceName(),     // remove backend info
                     uri.getAuthority(),
                     uri.getPath(),
                     uri.getQuery(),
diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/namespace/TestNamespaceBuilder.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/namespace/TestNamespaceBuilder.java
index 7ee7cb3..b905c41 100644
--- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/namespace/TestNamespaceBuilder.java
+++ b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/namespace/TestNamespaceBuilder.java
@@ -28,9 +28,6 @@ import org.apache.distributedlog.api.namespace.Namespace;
 import org.apache.distributedlog.api.namespace.NamespaceBuilder;
 import org.junit.Test;
 
-
-
-
 /**
  * Test Namespace Builder.
  */
diff --git a/stream/server/src/main/java/org/apache/bookkeeper/stream/cluster/StreamCluster.java b/stream/server/src/main/java/org/apache/bookkeeper/stream/cluster/StreamCluster.java
index ff0cda2..e5a6df4 100644
--- a/stream/server/src/main/java/org/apache/bookkeeper/stream/cluster/StreamCluster.java
+++ b/stream/server/src/main/java/org/apache/bookkeeper/stream/cluster/StreamCluster.java
@@ -29,11 +29,13 @@ import java.util.List;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
+import java.util.stream.Collectors;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.bookkeeper.clients.StorageClientBuilder;
 import org.apache.bookkeeper.clients.admin.StorageAdminClient;
 import org.apache.bookkeeper.clients.config.StorageClientSettings;
 import org.apache.bookkeeper.clients.exceptions.NamespaceExistsException;
+import org.apache.bookkeeper.clients.utils.NetUtils;
 import org.apache.bookkeeper.common.component.AbstractLifecycleComponent;
 import org.apache.bookkeeper.common.component.LifecycleComponent;
 import org.apache.bookkeeper.conf.ServerConfiguration;
@@ -226,12 +228,18 @@ public class StreamCluster
         executor.shutdown();
     }
 
+
     private void createDefaultNamespaces() throws Exception {
+        String serviceUri = String.format(
+            "bk://%s/",
+            getRpcEndpoints().stream()
+                .map(endpoint -> NetUtils.endpointToString(endpoint))
+                .collect(Collectors.joining(",")));
         StorageClientSettings settings = StorageClientSettings.newBuilder()
-            .addEndpoints(getRpcEndpoints().toArray(new Endpoint[getRpcEndpoints().size()]))
+            .serviceUri(serviceUri)
             .usePlaintext(true)
             .build();
-        log.info("RpcEndpoints are : {}", settings.endpoints());
+        log.info("Service uri are : {}", serviceUri);
         String namespaceName = "default";
         try (StorageAdminClient admin = StorageClientBuilder.newBuilder()
             .withSettings(settings)
diff --git a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/StreamClusterTestBase.java b/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/StreamClusterTestBase.java
index fe7c914..a7d8549 100644
--- a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/StreamClusterTestBase.java
+++ b/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/StreamClusterTestBase.java
@@ -78,8 +78,13 @@ public abstract class StreamClusterTestBase extends BookKeeperClusterTestBase {
     //
 
     protected static StorageClientSettings newStorageClientSettings() {
+        String serviceUri = String.format(
+            "bk://%s/",
+            getExsternalStreamEndpoints().stream()
+                .map(endpoint -> NetUtils.endpointToString(endpoint))
+                .collect(Collectors.joining(",")));
         return StorageClientSettings.newBuilder()
-            .addEndpoints(getExsternalStreamEndpoints().toArray(new Endpoint[getNumBookies()]))
+            .serviceUri(serviceUri)
             .endpointResolver(endpoint -> {
                 String internalEndpointStr = NetUtils.endpointToString(endpoint);
                 String externalEndpointStr =

-- 
To stop receiving notification emails like this one, please contact
sijie@apache.org.

[bookkeeper] 01/09: Provide the flag to allow ignoring startup failures on loading extra server components

Posted by si...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sijie pushed a commit to branch branch-4.7
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git

commit 1ae9772a30292f378d0ca9e68e2371badc6a99f2
Author: Sijie Guo <si...@apache.org>
AuthorDate: Fri May 25 11:10:22 2018 -0700

    Provide the flag to allow ignoring startup failures on loading extra server components
    
    Descriptions of the changes in this PR:
    
    Addressed the comments in apache/bookkeeper#1420
    
    Author: Sijie Guo <si...@apache.org>
    
    Reviewers: Enrico Olivelli <eo...@gmail.com>, Jia Zhai <None>
    
    This closes #1426 from sijie/flag_to_allow_silent_failures
---
 bookkeeper-dist/src/assemble/bin-all.xml           |  6 +++
 bookkeeper-dist/src/assemble/bin-server.xml        |  6 +++
 .../bookkeeper/conf/ServerConfiguration.java       | 29 ++++++++++++-
 .../java/org/apache/bookkeeper/server/Main.java    |  8 +++-
 .../org/apache/bookkeeper/server/TestMain.java     | 49 ++++++++++++++++++++++
 conf/bk_server.conf                                |  5 +++
 site/_data/config/bk_server.yaml                   |  3 ++
 7 files changed, 103 insertions(+), 3 deletions(-)

diff --git a/bookkeeper-dist/src/assemble/bin-all.xml b/bookkeeper-dist/src/assemble/bin-all.xml
index 4a7c4dc..54cd125 100644
--- a/bookkeeper-dist/src/assemble/bin-all.xml
+++ b/bookkeeper-dist/src/assemble/bin-all.xml
@@ -114,6 +114,12 @@
         <exclude>io.netty:netty-tcnative-boringssl-static</exclude>
         <exclude>io.netty:netty-transport-native-epoll</exclude>
         <exclude>io.netty:netty-transport</exclude>
+        <!-- All these dependencies are already included in stream-storage-java-client -->
+        <exclude>org.apache.bookkeeper:stream-storage-common</exclude>
+        <exclude>org.apache.bookkeeper:stream-storage-proto</exclude>
+        <exclude>org.apache.bookkeeper:stream-storage-api</exclude>
+        <exclude>org.apache.bookkeeper:stream-storage-java-client-base</exclude>
+        <exclude>org.apache.bookkeeper:stream-storage-java-kv-client</exclude>
       </excludes>
     </dependencySet>
   </dependencySets>
diff --git a/bookkeeper-dist/src/assemble/bin-server.xml b/bookkeeper-dist/src/assemble/bin-server.xml
index ce5a646..693fda6 100644
--- a/bookkeeper-dist/src/assemble/bin-server.xml
+++ b/bookkeeper-dist/src/assemble/bin-server.xml
@@ -103,6 +103,12 @@
         <exclude>io.netty:netty-resolver-dns</exclude>
         <exclude>io.netty:netty-tcnative-boringssl-static</exclude>
         <exclude>io.netty:netty-transport</exclude>
+        <!-- All these dependencies are already included in stream-storage-java-client -->
+        <exclude>org.apache.bookkeeper:stream-storage-common</exclude>
+        <exclude>org.apache.bookkeeper:stream-storage-proto</exclude>
+        <exclude>org.apache.bookkeeper:stream-storage-api</exclude>
+        <exclude>org.apache.bookkeeper:stream-storage-java-client-base</exclude>
+        <exclude>org.apache.bookkeeper:stream-storage-java-kv-client</exclude>
       </excludes>
     </dependencySet>
   </dependencySets>
diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/ServerConfiguration.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/ServerConfiguration.java
index 904ca3f..3e4749c 100644
--- a/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/ServerConfiguration.java
+++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/ServerConfiguration.java
@@ -18,6 +18,7 @@
 package org.apache.bookkeeper.conf;
 
 import com.google.common.annotations.Beta;
+import com.google.common.base.Strings;
 import java.io.File;
 import java.util.concurrent.TimeUnit;
 import org.apache.bookkeeper.bookie.InterleavedLedgerStorage;
@@ -174,6 +175,8 @@ public class ServerConfiguration extends AbstractConfiguration<ServerConfigurati
 
     // Lifecycle Components
     protected static final String EXTRA_SERVER_COMPONENTS = "extraServerComponents";
+    protected static final String IGNORE_EXTRA_SERVER_COMPONENTS_STARTUP_FAILURES =
+        "ignoreExtraServerComponentsStartupFailures";
 
     // Registration
     protected static final String REGISTRATION_MANAGER_CLASS = "registrationManagerClass";
@@ -2653,7 +2656,8 @@ public class ServerConfiguration extends AbstractConfiguration<ServerConfigurati
      * @return the extra list of server lifecycle components to enable on a bookie server.
      */
     public String[] getExtraServerComponents() {
-        if (!this.containsKey(EXTRA_SERVER_COMPONENTS)) {
+        String extraServerComponentsStr = getString(EXTRA_SERVER_COMPONENTS);
+        if (Strings.isNullOrEmpty(extraServerComponentsStr)) {
             return null;
         }
         return this.getStringArray(EXTRA_SERVER_COMPONENTS);
@@ -2672,6 +2676,29 @@ public class ServerConfiguration extends AbstractConfiguration<ServerConfigurati
     }
 
     /**
+     * Return the flag whether to ignore startup failures on loading server components specified at
+     * {@link #getExtraServerComponents()}.
+     *
+     * @return the flag whether to ignore startup failures on loading server components specified at
+     * {@link #getExtraServerComponents()}. The default value is <tt>false</tt>.
+     */
+    public boolean getIgnoreExtraServerComponentsStartupFailures() {
+        return getBoolean(IGNORE_EXTRA_SERVER_COMPONENTS_STARTUP_FAILURES, false);
+    }
+
+    /**
+     * Set the flag whether to ignore startup failures on loading server components specified at
+     * {@link #getExtraServerComponents()}.
+     *
+     * @param enabled flag to enable/disable ignoring startup failures on loading server components.
+     * @return server configuration.
+     */
+    public ServerConfiguration setIgnoreExtraServerComponentsStartupFailures(boolean enabled) {
+        setProperty(IGNORE_EXTRA_SERVER_COMPONENTS_STARTUP_FAILURES, enabled);
+        return this;
+    }
+
+    /**
      * Set registration manager class.
      *
      * @param regManagerClass
diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/server/Main.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/server/Main.java
index 1ef56de..ae92955 100644
--- a/bookkeeper-server/src/main/java/org/apache/bookkeeper/server/Main.java
+++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/server/Main.java
@@ -338,8 +338,12 @@ public class Main {
                     log.info("Load lifecycle component : {}", component.getClass().getName());
                 }
             } catch (Exception e) {
-                log.info("Failed to load extra components '{}' - {}. Continuing without those components.",
-                    StringUtils.join(extraComponents), e.getMessage());
+                if (conf.getServerConf().getIgnoreExtraServerComponentsStartupFailures()) {
+                    log.info("Failed to load extra components '{}' - {}. Continuing without those components.",
+                        StringUtils.join(extraComponents), e.getMessage());
+                } else {
+                    throw e;
+                }
             }
         }
 
diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/TestMain.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/TestMain.java
index 8027511..d5253fd 100644
--- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/TestMain.java
+++ b/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/TestMain.java
@@ -22,6 +22,7 @@ package org.apache.bookkeeper.server;
 import static org.apache.bookkeeper.server.Main.buildBookieServer;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -95,4 +96,52 @@ public class TestMain {
         verify(mockServer, times(1)).shutdown();
     }
 
+    @Test
+    public void testIgnoreExtraServerComponentsStartupFailures() throws Exception {
+        ServerConfiguration serverConf = new ServerConfiguration()
+            .setAutoRecoveryDaemonEnabled(false)
+            .setHttpServerEnabled(false)
+            .setExtraServerComponents(new String[] { "bad-server-component"})
+            .setIgnoreExtraServerComponentsStartupFailures(true);
+        BookieConfiguration conf = new BookieConfiguration(serverConf);
+
+        BookieServer mockServer = PowerMockito.mock(BookieServer.class);
+        whenNew(BookieServer.class)
+            .withArguments(any(ServerConfiguration.class), any(StatsLogger.class))
+            .thenReturn(mockServer);
+
+        LifecycleComponentStack stack = buildBookieServer(conf);
+        assertEquals(2, stack.getNumComponents());
+
+        stack.start();
+        verify(mockServer, times(1)).start();
+
+        stack.stop();
+
+        stack.close();
+        verify(mockServer, times(1)).shutdown();
+    }
+
+    @Test
+    public void testExtraServerComponentsStartupFailures() throws Exception {
+        ServerConfiguration serverConf = new ServerConfiguration()
+            .setAutoRecoveryDaemonEnabled(false)
+            .setHttpServerEnabled(false)
+            .setExtraServerComponents(new String[] { "bad-server-component"})
+            .setIgnoreExtraServerComponentsStartupFailures(false);
+        BookieConfiguration conf = new BookieConfiguration(serverConf);
+
+        BookieServer mockServer = PowerMockito.mock(BookieServer.class);
+        whenNew(BookieServer.class)
+            .withArguments(any(ServerConfiguration.class), any(StatsLogger.class))
+            .thenReturn(mockServer);
+
+        try {
+            buildBookieServer(conf);
+            fail("Should fail to start bookie server if `ignoreExtraServerComponentsStartupFailures` is set to false");
+        } catch (RuntimeException re) {
+            assertTrue(re.getCause() instanceof ClassNotFoundException);
+        }
+    }
+
 }
diff --git a/conf/bk_server.conf b/conf/bk_server.conf
index 6e3c1b4..10c7783 100755
--- a/conf/bk_server.conf
+++ b/conf/bk_server.conf
@@ -97,6 +97,11 @@ bookiePort=3181
 # extraServerComponents=org.apache.bookkeeper.stream.server.StreamStorageLifecycleComponent
 extraServerComponents=
 
+# Whether the bookie should ignore startup failures on loading server components specified
+# by `extraServerComponents`. The default value is `false`.
+#
+# ignoreExtraServerComponentsStartupFailures=false
+
 #############################################################################
 ## Thread settings
 #############################################################################
diff --git a/site/_data/config/bk_server.yaml b/site/_data/config/bk_server.yaml
index fd3ab7a..01d82f3 100644
--- a/site/_data/config/bk_server.yaml
+++ b/site/_data/config/bk_server.yaml
@@ -44,6 +44,9 @@ groups:
   - param: extraServerComponents
     description: Configure a list of extra server components to enable and load on a bookie server. This provides a plugin mechanism to run extra server components along with a bookie server.
     default: ''
+  - param: ignoreExtraServerComponentsStartupFailures
+    description: Whether the bookie should ignore startup failures on loading server components specified by `extraServerComponents`.
+    default: 'false'
 
 - name: Worker thread settings
   params:

-- 
To stop receiving notification emails like this one, please contact
sijie@apache.org.

[bookkeeper] 02/09: Update bookkeeper dependencies : netty/protobuf/grpc

Posted by si...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sijie pushed a commit to branch branch-4.7
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git

commit 3cf0be80fff1a553b7614eead8bf185569e085f0
Author: Sijie Guo <si...@apache.org>
AuthorDate: Fri May 25 15:02:03 2018 -0700

    Update bookkeeper dependencies : netty/protobuf/grpc
    
    Descriptions of the changes in this PR:
    
    *Motivation*
    
    The netty version in bookkeeper is a bit dated than the version in pulsar.
    Hence the grpc version is limited to the version that use same netty version.
    It causes issues at pulsar using bookkeeper, because pulsar has been using
    a newer version for longer time. This causes conflicts when pulsar client and
    grpc are used together without proper shading.
    
    *Solution*
    
    Upgrade netty/protobuf/grpc dependencies.
    
    - update netty from `4.1.12` to `4.1.22`, which is the one grpc is using and closer to the one that pulsar is using.
    - update grpc from `1.5.0` to `1.12.0`, which is using netty `4.1.22` and protobuf `3.5.1`.
    - update protobuf from `3.4.0` to `3.5.1`
    
    Related Issue: apache/pulsar#1844
    
    Author: Sijie Guo <si...@apache.org>
    
    Reviewers: Enrico Olivelli <eo...@gmail.com>, Jia Zhai <None>, Matteo Merli <mm...@apache.org>
    
    This closes #1441 from sijie/bump_grpc_version
---
 bookkeeper-dist/src/assemble/bin-all.xml           |  7 +-
 bookkeeper-dist/src/assemble/bin-server.xml        |  7 +-
 .../src/main/resources/LICENSE-all.bin.txt         | 93 +++++++++++-----------
 .../src/main/resources/LICENSE-server.bin.txt      | 92 ++++++++++-----------
 .../src/main/resources/NOTICE-all.bin.txt          |  2 +-
 .../src/main/resources/NOTICE-server.bin.txt       |  2 +-
 .../LICENSE                                        |  0
 .../LICENSE.base64.txt                             |  0
 .../LICENSE.jbzip2.txt                             |  0
 .../LICENSE.jfastlz.txt                            |  0
 .../LICENSE.jsr166y.txt                            |  0
 .../LICENSE.libdivsufsort.txt                      |  0
 .../LICENSE.protobuf.txt                           |  0
 .../LICENSE.slf4j.txt                              |  0
 .../LICENSE.webbit.txt                             |  0
 .../src/main/resources/deps/protobuf-3.3.1/LICENSE | 32 --------
 .../{protobuf-3.4.0 => protobuf-3.5.1}/LICENSE     |  0
 .../bookkeeper/proto/BookieProtoEncodingTest.java  | 19 +++--
 pom.xml                                            | 16 ++--
 .../clients/impl/channel/StorageServerChannel.java |  1 +
 .../clients/impl/internal/LocationClientImpl.java  |  1 +
 .../apache/bookkeeper/clients/utils/GrpcUtils.java | 18 ++++-
 .../common/grpc/proxy/PingPongServiceTestBase.java |  4 +-
 23 files changed, 141 insertions(+), 153 deletions(-)

diff --git a/bookkeeper-dist/src/assemble/bin-all.xml b/bookkeeper-dist/src/assemble/bin-all.xml
index 54cd125..3a76012 100644
--- a/bookkeeper-dist/src/assemble/bin-all.xml
+++ b/bookkeeper-dist/src/assemble/bin-all.xml
@@ -54,15 +54,14 @@
       <directory>../src/main/resources/deps</directory>
       <outputDirectory>/deps</outputDirectory>
       <includes>
-        <include>google-auth-library-credentials-0.4.0/LICENSE</include>
+        <include>google-auth-library-credentials-0.9.0/LICENSE</include>
         <include>javax.servlet-api-3.1.0/CDDL+GPL-1.1</include>
         <include>jsr-305/LICENSE</include>
         <include>netty-3.10.1.Final/*</include>
-        <include>netty-4.1.12.Final/*</include>
+        <include>netty-4.1.22.Final/*</include>
         <include>paranamer-2.8/LICENSE.txt</include>
         <include>protobuf-3.0.0/LICENSE</include>
-        <include>protobuf-3.3.1/LICENSE</include>
-        <include>protobuf-3.4.0/LICENSE</include>
+        <include>protobuf-3.5.1/LICENSE</include>
         <include>scala-library-2.11.7/LICENSE.md</include>
         <include>scala-parser-combinators_2.11-1.0.4/LICENSE.md</include>
         <include>scala-reflect-2.11.8/LICENSE.md</include>
diff --git a/bookkeeper-dist/src/assemble/bin-server.xml b/bookkeeper-dist/src/assemble/bin-server.xml
index 693fda6..10eb30c 100644
--- a/bookkeeper-dist/src/assemble/bin-server.xml
+++ b/bookkeeper-dist/src/assemble/bin-server.xml
@@ -49,12 +49,11 @@
       <directory>../src/main/resources/deps</directory>
       <outputDirectory>/deps</outputDirectory>
       <includes>
-        <include>google-auth-library-credentials-0.4.0/LICENSE</include>
+        <include>google-auth-library-credentials-0.9.0/LICENSE</include>
         <include>javax.servlet-api-3.1.0/CDDL+GPL-1.1</include>
-        <include>netty-4.1.12.Final/*</include>
+        <include>netty-4.1.22.Final/*</include>
         <include>protobuf-3.0.0/LICENSE</include>
-        <include>protobuf-3.3.1/LICENSE</include>
-        <include>protobuf-3.4.0/LICENSE</include>
+        <include>protobuf-3.5.1/LICENSE</include>
         <include>slf4j-1.7.25/LICENSE.txt</include>
       </includes>
       <fileMode>644</fileMode>
diff --git a/bookkeeper-dist/src/main/resources/LICENSE-all.bin.txt b/bookkeeper-dist/src/main/resources/LICENSE-all.bin.txt
index 289916d..98159e7 100644
--- a/bookkeeper-dist/src/main/resources/LICENSE-all.bin.txt
+++ b/bookkeeper-dist/src/main/resources/LICENSE-all.bin.txt
@@ -250,7 +250,7 @@ Apache Software License, Version 2.
 - lib/io.dropwizard.metrics-metrics-graphite-3.1.0.jar [21]
 - lib/io.dropwizard.metrics-metrics-jvm-3.1.0.jar [21]
 - lib/io.netty-netty-3.10.1.Final.jar [22]
-- lib/io.netty-netty-all-4.1.12.Final.jar [23]
+- lib/io.netty-netty-all-4.1.22.Final.jar [23]
 - lib/io.prometheus-simpleclient-0.0.21.jar [24]
 - lib/io.prometheus-simpleclient_common-0.0.21.jar [24]
 - lib/io.prometheus-simpleclient_hotspot-0.0.21.jar [24]
@@ -276,25 +276,28 @@ Apache Software License, Version 2.
 - lib/net.jpountz.lz4-lz4-1.3.0.jar [38]
 - lib/org.codehaus.jackson-jackson-core-asl-1.9.11.jar [39]
 - lib/org.codehaus.jackson-jackson-mapper-asl-1.9.11.jar [40]
-- lib/com.google.api.grpc-proto-google-common-protos-0.1.9.jar [41]
+- lib/com.google.api.grpc-proto-google-common-protos-1.0.0.jar [41]
 - lib/com.google.code.gson-gson-2.7.jar [42]
-- lib/com.google.instrumentation-instrumentation-api-0.4.3.jar [43]
+- lib/io.opencensus-opencensus-api-0.11.0.jar [43]
+- lib/io.opencensus-opencensus-contrib-grpc-metrics-0.11.0.jar [43]
 - lib/com.squareup.okhttp-okhttp-2.5.0.jar [44]
-- lib/com.squareup.okio-okio-1.6.0.jar [45]
-- lib/io.grpc-grpc-all-1.5.0.jar [46]
-- lib/io.grpc-grpc-auth-1.5.0.jar [46]
-- lib/io.grpc-grpc-context-1.5.0.jar [46]
-- lib/io.grpc-grpc-core-1.5.0.jar [46]
-- lib/io.grpc-grpc-netty-1.5.0.jar [46]
-- lib/io.grpc-grpc-okhttp-1.5.0.jar [46]
-- lib/io.grpc-grpc-protobuf-1.5.0.jar [46]
-- lib/io.grpc-grpc-protobuf-lite-1.5.0.jar [46]
-- lib/io.grpc-grpc-protobuf-nano-1.5.0.jar [46]
-- lib/io.grpc-grpc-stub-1.5.0.jar [46]
+- lib/com.squareup.okio-okio-1.13.0.jar [45]
+- lib/io.grpc-grpc-all-1.12.0.jar [46]
+- lib/io.grpc-grpc-auth-1.12.0.jar [46]
+- lib/io.grpc-grpc-context-1.12.0.jar [46]
+- lib/io.grpc-grpc-core-1.12.0.jar [46]
+- lib/io.grpc-grpc-netty-1.12.0.jar [46]
+- lib/io.grpc-grpc-okhttp-1.12.0.jar [46]
+- lib/io.grpc-grpc-protobuf-1.12.0.jar [46]
+- lib/io.grpc-grpc-protobuf-lite-1.12.0.jar [46]
+- lib/io.grpc-grpc-protobuf-nano-1.12.0.jar [46]
+- lib/io.grpc-grpc-stub-1.12.0.jar [46]
+- lib/io.grpc-grpc-testing-1.12.0.jar [46]
 - lib/org.apache.curator-curator-client-4.0.1.jar [47]
 - lib/org.apache.curator-curator-framework-4.0.1.jar [47]
 - lib/org.apache.curator-curator-recipes-4.0.1.jar [47]
 - lib/org.inferred-freebuilder-1.14.9.jar [48]
+- lib/com.google.errorprone-error_prone_annotations-2.1.2.jar [49]
 
 [1] Source available at https://github.com/FasterXML/jackson-annotations/tree/jackson-annotations-2.8.9
 [2] Source available at https://github.com/FasterXML/jackson-core/tree/jackson-core-2.8.9
@@ -318,7 +321,7 @@ Apache Software License, Version 2.
 [20] Source available at https://github.com/twitter/util/tree/util-6.43.0
 [21] Source available at https://github.com/dropwizard/metrics/tree/v3.1.0
 [22] Source available at https://bintray.com/netty/downloads/download_file?file_path=netty-3.10.1.Final-dist.tar.bz2
-[23] Source available at https://github.com/netty/netty/tree/netty-4.1.12.Final
+[23] Source available at https://github.com/netty/netty/tree/netty-4.1.22.Final
 [24] Source available at https://github.com/prometheus/client_java/tree/parent-0.0.21
 [25] Source available at https://github.com/vert-x3/vertx-auth/tree/3.4.1
 [26] Source available at https://github.com/eclipse/vert.x/tree/3.4.1
@@ -337,12 +340,13 @@ Apache Software License, Version 2.
 [40] Source available at https://github.com/codehaus/jackson/tree/1.9
 [41] Source available at https://github.com/googleapis/googleapis
 [42] Source available at https://github.com/google/gson/tree/gson-parent-2.7
-[43] Source available at https://github.com/census-instrumentation/opencensus-java/tree/v0.4.3
+[43] Source available at https://github.com/census-instrumentation/opencensus-java/tree/v0.11.0
 [44] Source available at https://github.com/square/okhttp/tree/parent-2.5.0
-[45] Source available at https://github.com/square/okio/tree/okio-parent-1.6.0
-[46] Source available at https://github.com/grpc/grpc-java/tree/v1.5.0
+[45] Source available at https://github.com/square/okio/tree/okio-parent-1.13.0
+[46] Source available at https://github.com/grpc/grpc-java/tree/v1.12.0
 [47] Source available at https://github.com/apache/curator/tree/apache-curator-4.0.1
 [48] Source available at https://github.com/inferred/FreeBuilder/tree/v1.14.9
+[49] Source available at https://github.com/google/error-prone/tree/v2.1.2
 
 
 ------------------------------------------------------------------------------------
@@ -380,71 +384,71 @@ WebSocket and HTTP server:
     * https://github.com/joewalnes/webbit
 
 ------------------------------------------------------------------------------------
-lib/io.netty-netty-all-4.1.12.Final.jar bundles some 3rd party dependencies
+lib/io.netty-netty-all-4.1.22.Final.jar bundles some 3rd party dependencies
 
-lib/io.netty-netty-all-4.1.12.Final.jar contains the extensions to Java Collections Framework which has
+lib/io.netty-netty-all-4.1.22.Final.jar contains the extensions to Java Collections Framework which has
 been derived from the works by JSR-166 EG, Doug Lea, and Jason T. Greene:
 
   * LICENSE:
-    * deps/netty-4.1.12.Final/LICENSE.jsr166y.txt (Public Domain)
+    * deps/netty-4.1.22.Final/LICENSE.jsr166y.txt (Public Domain)
   * HOMEPAGE:
     * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/
     * http://viewvc.jboss.org/cgi-bin/viewvc.cgi/jbosscache/experimental/jsr166/
 
-lib/io.netty-netty-all-4.1.12.Final.jar contains a modified version of Robert Harder's Public Domain
+lib/io.netty-netty-all-4.1.22.Final.jar contains a modified version of Robert Harder's Public Domain
 Base64 Encoder and Decoder, which can be obtained at:
 
   * LICENSE:
-    * deps/netty-4.1.12.Final/LICENSE.base64.txt (Public Domain)
+    * deps/netty-4.1.22.Final/LICENSE.base64.txt (Public Domain)
   * HOMEPAGE:
     * http://iharder.sourceforge.net/current/java/base64/
 
-lib/io.netty-netty-all-4.1.12.Final.jar contains a modified portion of 'Webbit', an event based  
+lib/io.netty-netty-all-4.1.22.Final.jar contains a modified portion of 'Webbit', an event based  
 WebSocket and HTTP server, which can be obtained at:
 
   * LICENSE:
-    * deps/netty-4.1.12.Final/LICENSE.webbit.txt (BSD License)
+    * deps/netty-4.1.22.Final/LICENSE.webbit.txt (BSD License)
   * HOMEPAGE:
     * https://github.com/joewalnes/webbit
 
-lib/io.netty-netty-all-4.1.12.Final.jar contains a modified portion of 'SLF4J', a simple logging
+lib/io.netty-netty-all-4.1.22.Final.jar contains a modified portion of 'SLF4J', a simple logging
 facade for Java, which can be obtained at:
 
   * LICENSE:
-    * deps/netty-4.1.12.Final/LICENSE.slf4j.txt (MIT License)
+    * deps/netty-4.1.22.Final/LICENSE.slf4j.txt (MIT License)
   * HOMEPAGE:
     * http://www.slf4j.org/
 
-lib/io.netty-netty-all-4.1.12.Final.jar contains a modified portion of 'jbzip2', a Java bzip2 compression
+lib/io.netty-netty-all-4.1.22.Final.jar contains a modified portion of 'jbzip2', a Java bzip2 compression
 and decompression library written by Matthew J. Francis. It can be obtained at:
 
   * LICENSE:
-    * deps/netty-4.1.12.Final/LICENSE.jbzip2.txt (MIT License)
+    * deps/netty-4.1.22.Final/LICENSE.jbzip2.txt (MIT License)
   * HOMEPAGE:
     * https://code.google.com/p/jbzip2/
 
-lib/io.netty-netty-all-4.1.12.Final.jar contains a modified portion of 'libdivsufsort', a C API library to construct
+lib/io.netty-netty-all-4.1.22.Final.jar contains a modified portion of 'libdivsufsort', a C API library to construct
 the suffix array and the Burrows-Wheeler transformed string for any input string of
 a constant-size alphabet written by Yuta Mori. It can be obtained at:
 
   * LICENSE:
-    * deps/netty-4.1.12.Final/LICENSE.libdivsufsort.txt (MIT License)
+    * deps/netty-4.1.22.Final/LICENSE.libdivsufsort.txt (MIT License)
   * HOMEPAGE:
     * https://github.com/y-256/libdivsufsort
 
-lib/io.netty-netty-all-4.1.12.Final.jar contains a modified portion of 'jfastlz', a Java port of FastLZ compression
+lib/io.netty-netty-all-4.1.22.Final.jar contains a modified portion of 'jfastlz', a Java port of FastLZ compression
 and decompression library written by William Kinney. It can be obtained at:
 
   * LICENSE:
-    * deps/netty-4.1.12.Final/LICENSE.jfastlz.txt (MIT License)
+    * deps/netty-4.1.22.Final/LICENSE.jfastlz.txt (MIT License)
   * HOMEPAGE:
     * https://code.google.com/p/jfastlz/
 
-lib/io.netty-netty-all-4.1.12.Final.jar contains a modified portion of and optionally depends on 'Protocol Buffers', Google's data
+lib/io.netty-netty-all-4.1.22.Final.jar contains a modified portion of and optionally depends on 'Protocol Buffers', Google's data
 interchange format, which can be obtained at:
 
   * LICENSE:
-    * deps/netty-4.1.12.Final/LICENSE.protobuf.txt (New BSD License)
+    * deps/netty-4.1.22.Final/LICENSE.protobuf.txt (New BSD License)
   * HOMEPAGE:
     * https://github.com/google/protobuf
 
@@ -489,18 +493,15 @@ Source available at https://storage.googleapis.com/google-code-archive-source/v2
 This product bundles Google Protocal Buffers, which is available under a "3-clause BSD"
 license.
 
-Bundled as lib/com.google.protobuf-protobuf-java-3.4.0.jar
-Source available at https://github.com/google/protobuf/tree/v3.4.0
-For details, see deps/protobuf-3.4.0/LICENSE.
+Bundled as
+  - lib/com.google.protobuf-protobuf-java-3.5.1.jar
+  - lib/com.google.protobuf-protobuf-java-util-3.5.1.jar
+Source available at https://github.com/google/protobuf/tree/v3.5.1
+For details, see deps/protobuf-3.5.1/LICENSE.
 
 Bundled as lib/com.google.protobuf.nano-protobuf-javanano-3.0.0-alpha-5.jar
 Source available at https://github.com/google/protobuf/tree/3.0.0-pre
 For details, see deps/protobuf-3.0.0/LICENSE.
-
-Bundled as com.google.protobuf-protobuf-java-util-3.3.1.jar
-Source available at https://github.com/google/protobuf/tree/v3.3.1
-For details, see deps/protobuf-3.3.1/LICENSE.
-
 ------------------------------------------------------------------------------------
 This product bundles Paranamer, which is available under a "3-clause BSD" license.
 For details, see deps/paranamer-2.8/LICENSE.txt.
@@ -541,9 +542,9 @@ Bundled as
 Source available at https://github.com/qos-ch/slf4j/tree/v_1.7.25
 ------------------------------------------------------------------------------------
 This product bundles the Google Auth Library, which is available under a "3-clause BSD"
-license. For details, see deps/google-auth-library-credentials-0.4.0/LICENSE
+license. For details, see deps/google-auth-library-credentials-0.9.0/LICENSE
 
 Bundled as
-  - lib/com.google.auth-google-auth-library-credentials-0.4.0.jar
-Source available at https://github.com/google/google-auth-library-java/tree/0.4.0
+  - lib/com.google.auth-google-auth-library-credentials-0.9.0.jar
+Source available at https://github.com/google/google-auth-library-java/tree/0.9.0
 
diff --git a/bookkeeper-dist/src/main/resources/LICENSE-server.bin.txt b/bookkeeper-dist/src/main/resources/LICENSE-server.bin.txt
index 168f8fd..e970577 100644
--- a/bookkeeper-dist/src/main/resources/LICENSE-server.bin.txt
+++ b/bookkeeper-dist/src/main/resources/LICENSE-server.bin.txt
@@ -215,7 +215,7 @@ Apache Software License, Version 2.
 - lib/commons-io-commons-io-2.4.jar [8]
 - lib/commons-lang-commons-lang-2.6.jar [9]
 - lib/commons-logging-commons-logging-1.1.1.jar [10]
-- lib/io.netty-netty-all-4.1.12.Final.jar [11]
+- lib/io.netty-netty-all-4.1.22.Final.jar [11]
 - lib/io.prometheus-simpleclient-0.0.21.jar [12]
 - lib/io.prometheus-simpleclient_common-0.0.21.jar [12]
 - lib/io.prometheus-simpleclient_hotspot-0.0.21.jar [12]
@@ -241,25 +241,28 @@ Apache Software License, Version 2.
 - lib/net.jpountz.lz4-lz4-1.3.0.jar [25]
 - lib/org.codehaus.jackson-jackson-core-asl-1.9.11.jar [26]
 - lib/org.codehaus.jackson-jackson-mapper-asl-1.9.11.jar [27]
-- lib/com.google.api.grpc-proto-google-common-protos-0.1.9.jar [28]
+- lib/com.google.api.grpc-proto-google-common-protos-1.0.0.jar [28]
 - lib/com.google.code.gson-gson-2.7.jar [29]
-- lib/com.google.instrumentation-instrumentation-api-0.4.3.jar [30]
+- lib/io.opencensus-opencensus-api-0.11.0.jar [30]
+- lib/io.opencensus-opencensus-contrib-grpc-metrics-0.11.0.jar [30]
 - lib/com.squareup.okhttp-okhttp-2.5.0.jar [31]
-- lib/com.squareup.okio-okio-1.6.0.jar [32]
-- lib/io.grpc-grpc-all-1.5.0.jar [33]
-- lib/io.grpc-grpc-auth-1.5.0.jar [33]
-- lib/io.grpc-grpc-context-1.5.0.jar [33]
-- lib/io.grpc-grpc-core-1.5.0.jar [33]
-- lib/io.grpc-grpc-netty-1.5.0.jar [33]
-- lib/io.grpc-grpc-okhttp-1.5.0.jar [33]
-- lib/io.grpc-grpc-protobuf-1.5.0.jar [33]
-- lib/io.grpc-grpc-protobuf-lite-1.5.0.jar [33]
-- lib/io.grpc-grpc-protobuf-nano-1.5.0.jar [33]
-- lib/io.grpc-grpc-stub-1.5.0.jar [33]
+- lib/com.squareup.okio-okio-1.13.0.jar [32]
+- lib/io.grpc-grpc-all-1.12.0.jar [33]
+- lib/io.grpc-grpc-auth-1.12.0.jar [33]
+- lib/io.grpc-grpc-context-1.12.0.jar [33]
+- lib/io.grpc-grpc-core-1.12.0.jar [33]
+- lib/io.grpc-grpc-netty-1.12.0.jar [33]
+- lib/io.grpc-grpc-okhttp-1.12.0.jar [33]
+- lib/io.grpc-grpc-protobuf-1.12.0.jar [33]
+- lib/io.grpc-grpc-protobuf-lite-1.12.0.jar [33]
+- lib/io.grpc-grpc-protobuf-nano-1.12.0.jar [33]
+- lib/io.grpc-grpc-stub-1.12.0.jar [33]
+- lib/io.grpc-grpc-testing-1.12.0.jar [33]
 - lib/org.apache.curator-curator-client-4.0.1.jar [34]
 - lib/org.apache.curator-curator-framework-4.0.1.jar [34]
 - lib/org.apache.curator-curator-recipes-4.0.1.jar [34]
 - lib/org.inferred-freebuilder-1.14.9.jar [35]
+- lib/com.google.errorprone-error_prone_annotations-2.1.2.jar [36]
 
 [1] Source available at https://github.com/FasterXML/jackson-annotations/tree/jackson-annotations-2.8.9
 [2] Source available at https://github.com/FasterXML/jackson-core/tree/jackson-core-2.8.9
@@ -271,7 +274,7 @@ Apache Software License, Version 2.
 [8] Source available at https://git-wip-us.apache.org/repos/asf?p=commons-io.git;a=tag;h=603579
 [9] Source available at https://git-wip-us.apache.org/repos/asf?p=commons-lang.git;a=tag;h=375459
 [10] Source available at http://svn.apache.org/viewvc/commons/proper/logging/tags/commons-logging-1.1.1/
-[11] Source available at https://github.com/netty/netty/tree/netty-4.1.12.Final
+[11] Source available at https://github.com/netty/netty/tree/netty-4.1.22.Final
 [12] Source available at https://github.com/prometheus/client_java/tree/parent-0.0.21
 [13] Source available at https://github.com/vert-x3/vertx-auth/tree/3.4.1
 [14] Source available at https://github.com/eclipse/vert.x/tree/3.4.1
@@ -290,79 +293,80 @@ Apache Software License, Version 2.
 [27] Source available at https://github.com/codehaus/jackson/tree/1.9
 [28] Source available at https://github.com/googleapis/googleapis
 [29] Source available at https://github.com/google/gson/tree/gson-parent-2.7
-[30] Source available at https://github.com/census-instrumentation/opencensus-java/tree/v0.4.3
+[30] Source available at https://github.com/census-instrumentation/opencensus-java/tree/v0.11.0
 [31] Source available at https://github.com/square/okhttp/tree/parent-2.5.0
-[32] Source available at https://github.com/square/okio/tree/okio-parent-1.6.0
-[33] Source available at https://github.com/grpc/grpc-java/tree/v1.5.0
+[32] Source available at https://github.com/square/okio/tree/okio-parent-1.13.0
+[33] Source available at https://github.com/grpc/grpc-java/tree/v1.12.0
 [34] Source available at https://github.com/apache/curator/tree/apache-curator-4.0.1
 [35] Source available at https://github.com/inferred/FreeBuilder/tree/v1.14.9
+[36] Source available at https://github.com/google/error-prone/tree/v2.1.2
 
 ------------------------------------------------------------------------------------
-lib/io.netty-netty-all-4.1.12.Final.jar bundles some 3rd party dependencies
+lib/io.netty-netty-all-4.1.22.Final.jar bundles some 3rd party dependencies
 
-lib/io.netty-netty-all-4.1.12.Final.jar contains the extensions to Java Collections Framework which has
+lib/io.netty-netty-all-4.1.22.Final.jar contains the extensions to Java Collections Framework which has
 been derived from the works by JSR-166 EG, Doug Lea, and Jason T. Greene:
 
   * LICENSE:
-    * deps/netty-4.1.12.Final/LICENSE.jsr166y.txt (Public Domain)
+    * deps/netty-4.1.22.Final/LICENSE.jsr166y.txt (Public Domain)
   * HOMEPAGE:
     * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/
     * http://viewvc.jboss.org/cgi-bin/viewvc.cgi/jbosscache/experimental/jsr166/
 
-lib/io.netty-netty-all-4.1.12.Final.jar contains a modified version of Robert Harder's Public Domain
+lib/io.netty-netty-all-4.1.22.Final.jar contains a modified version of Robert Harder's Public Domain
 Base64 Encoder and Decoder, which can be obtained at:
 
   * LICENSE:
-    * deps/netty-4.1.12.Final/LICENSE.base64.txt (Public Domain)
+    * deps/netty-4.1.22.Final/LICENSE.base64.txt (Public Domain)
   * HOMEPAGE:
     * http://iharder.sourceforge.net/current/java/base64/
 
-lib/io.netty-netty-all-4.1.12.Final.jar contains a modified portion of 'Webbit', an event based  
+lib/io.netty-netty-all-4.1.22.Final.jar contains a modified portion of 'Webbit', an event based  
 WebSocket and HTTP server, which can be obtained at:
 
   * LICENSE:
-    * deps/netty-4.1.12.Final/LICENSE.webbit.txt (BSD License)
+    * deps/netty-4.1.22.Final/LICENSE.webbit.txt (BSD License)
   * HOMEPAGE:
     * https://github.com/joewalnes/webbit
 
-lib/io.netty-netty-all-4.1.12.Final.jar contains a modified portion of 'SLF4J', a simple logging
+lib/io.netty-netty-all-4.1.22.Final.jar contains a modified portion of 'SLF4J', a simple logging
 facade for Java, which can be obtained at:
 
   * LICENSE:
-    * deps/netty-4.1.12.Final/LICENSE.slf4j.txt (MIT License)
+    * deps/netty-4.1.22.Final/LICENSE.slf4j.txt (MIT License)
   * HOMEPAGE:
     * http://www.slf4j.org/
 
-lib/io.netty-netty-all-4.1.12.Final.jar contains a modified portion of 'jbzip2', a Java bzip2 compression
+lib/io.netty-netty-all-4.1.22.Final.jar contains a modified portion of 'jbzip2', a Java bzip2 compression
 and decompression library written by Matthew J. Francis. It can be obtained at:
 
   * LICENSE:
-    * deps/netty-4.1.12.Final/LICENSE.jbzip2.txt (MIT License)
+    * deps/netty-4.1.22.Final/LICENSE.jbzip2.txt (MIT License)
   * HOMEPAGE:
     * https://code.google.com/p/jbzip2/
 
-lib/io.netty-netty-all-4.1.12.Final.jar contains a modified portion of 'libdivsufsort', a C API library to construct
+lib/io.netty-netty-all-4.1.22.Final.jar contains a modified portion of 'libdivsufsort', a C API library to construct
 the suffix array and the Burrows-Wheeler transformed string for any input string of
 a constant-size alphabet written by Yuta Mori. It can be obtained at:
 
   * LICENSE:
-    * deps/netty-4.1.12.Final/LICENSE.libdivsufsort.txt (MIT License)
+    * deps/netty-4.1.22.Final/LICENSE.libdivsufsort.txt (MIT License)
   * HOMEPAGE:
     * https://github.com/y-256/libdivsufsort
 
-lib/io.netty-netty-all-4.1.12.Final.jar contains a modified portion of 'jfastlz', a Java port of FastLZ compression
+lib/io.netty-netty-all-4.1.22.Final.jar contains a modified portion of 'jfastlz', a Java port of FastLZ compression
 and decompression library written by William Kinney. It can be obtained at:
 
   * LICENSE:
-    * deps/netty-4.1.12.Final/LICENSE.jfastlz.txt (MIT License)
+    * deps/netty-4.1.22.Final/LICENSE.jfastlz.txt (MIT License)
   * HOMEPAGE:
     * https://code.google.com/p/jfastlz/
 
-lib/io.netty-netty-all-4.1.12.Final.jar contains a modified portion of and optionally depends on 'Protocol Buffers', Google's data
+lib/io.netty-netty-all-4.1.22.Final.jar contains a modified portion of and optionally depends on 'Protocol Buffers', Google's data
 interchange format, which can be obtained at:
 
   * LICENSE:
-    * deps/netty-4.1.12.Final/LICENSE.protobuf.txt (New BSD License)
+    * deps/netty-4.1.22.Final/LICENSE.protobuf.txt (New BSD License)
   * HOMEPAGE:
     * https://github.com/google/protobuf
 
@@ -401,17 +405,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 This product bundles Google Protocal Buffers, which is available under a "3-clause BSD"
 license.
 
-Bundled as lib/com.google.protobuf-protobuf-java-3.4.0.jar
-Source available at https://github.com/google/protobuf/tree/v3.4.0
-For details, see deps/protobuf-3.4.0/LICENSE.
+Bundled as
+  - lib/com.google.protobuf-protobuf-java-3.5.1.jar
+  - lib/com.google.protobuf-protobuf-java-util-3.5.1.jar
+Source available at https://github.com/google/protobuf/tree/v3.5.1
+For details, see deps/protobuf-3.5.1/LICENSE.
 
 Bundled as lib/com.google.protobuf.nano-protobuf-javanano-3.0.0-alpha-5.jar
 Source available at https://github.com/google/protobuf/tree/3.0.0-pre
 For details, see deps/protobuf-3.0.0/LICENSE.
-
-Bundled as com.google.protobuf-protobuf-java-util-3.3.1.jar
-Source available at https://github.com/google/protobuf/tree/v3.3.1
-For details, see deps/protobuf-3.3.1/LICENSE.
 ------------------------------------------------------------------------------------
 This product bundles the JCP Standard Java Servlet API, which is available under a
 CDDL 1.1 license. For details, see deps/javax.servlet-api-3.1.0/CDDL+GPL-1.1.
@@ -428,8 +430,8 @@ Bundled as
 Source available at https://github.com/qos-ch/slf4j/tree/v_1.7.25
 ------------------------------------------------------------------------------------
 This product bundles the Google Auth Library, which is available under a "3-clause BSD"
-license. For details, see deps/google-auth-library-credentials-0.4.0/LICENSE
+license. For details, see deps/google-auth-library-credentials-0.9.0/LICENSE
 
 Bundled as
-  - lib/com.google.auth-google-auth-library-credentials-0.4.0.jar
-Source available at https://github.com/google/google-auth-library-java/tree/0.4.0
+  - lib/com.google.auth-google-auth-library-credentials-0.9.0.jar
+Source available at https://github.com/google/google-auth-library-java/tree/0.9.0
diff --git a/bookkeeper-dist/src/main/resources/NOTICE-all.bin.txt b/bookkeeper-dist/src/main/resources/NOTICE-all.bin.txt
index 7357414..d9984b6 100644
--- a/bookkeeper-dist/src/main/resources/NOTICE-all.bin.txt
+++ b/bookkeeper-dist/src/main/resources/NOTICE-all.bin.txt
@@ -45,7 +45,7 @@ License for the specific language governing permissions and limitations
 under the License.
 
 ------------------------------------------------------------------------------------
-- lib/io.netty-netty-all-4.1.12.Final.jar
+- lib/io.netty-netty-all-4.1.22.Final.jar
 
                             The Netty Project
                             =================
diff --git a/bookkeeper-dist/src/main/resources/NOTICE-server.bin.txt b/bookkeeper-dist/src/main/resources/NOTICE-server.bin.txt
index 905c4c1..1fd2f53 100644
--- a/bookkeeper-dist/src/main/resources/NOTICE-server.bin.txt
+++ b/bookkeeper-dist/src/main/resources/NOTICE-server.bin.txt
@@ -5,7 +5,7 @@ This product includes software developed at
 The Apache Software Foundation (http://www.apache.org/).
 
 ------------------------------------------------------------------------------------
-- lib/io.netty-netty-all-4.1.12.Final.jar
+- lib/io.netty-netty-all-4.1.22.Final.jar
 
                             The Netty Project
                             =================
diff --git a/bookkeeper-dist/src/main/resources/deps/google-auth-library-credentials-0.4.0/LICENSE b/bookkeeper-dist/src/main/resources/deps/google-auth-library-credentials-0.9.0/LICENSE
similarity index 100%
rename from bookkeeper-dist/src/main/resources/deps/google-auth-library-credentials-0.4.0/LICENSE
rename to bookkeeper-dist/src/main/resources/deps/google-auth-library-credentials-0.9.0/LICENSE
diff --git a/bookkeeper-dist/src/main/resources/deps/netty-4.1.12.Final/LICENSE.base64.txt b/bookkeeper-dist/src/main/resources/deps/netty-4.1.22.Final/LICENSE.base64.txt
similarity index 100%
rename from bookkeeper-dist/src/main/resources/deps/netty-4.1.12.Final/LICENSE.base64.txt
rename to bookkeeper-dist/src/main/resources/deps/netty-4.1.22.Final/LICENSE.base64.txt
diff --git a/bookkeeper-dist/src/main/resources/deps/netty-4.1.12.Final/LICENSE.jbzip2.txt b/bookkeeper-dist/src/main/resources/deps/netty-4.1.22.Final/LICENSE.jbzip2.txt
similarity index 100%
rename from bookkeeper-dist/src/main/resources/deps/netty-4.1.12.Final/LICENSE.jbzip2.txt
rename to bookkeeper-dist/src/main/resources/deps/netty-4.1.22.Final/LICENSE.jbzip2.txt
diff --git a/bookkeeper-dist/src/main/resources/deps/netty-4.1.12.Final/LICENSE.jfastlz.txt b/bookkeeper-dist/src/main/resources/deps/netty-4.1.22.Final/LICENSE.jfastlz.txt
similarity index 100%
rename from bookkeeper-dist/src/main/resources/deps/netty-4.1.12.Final/LICENSE.jfastlz.txt
rename to bookkeeper-dist/src/main/resources/deps/netty-4.1.22.Final/LICENSE.jfastlz.txt
diff --git a/bookkeeper-dist/src/main/resources/deps/netty-4.1.12.Final/LICENSE.jsr166y.txt b/bookkeeper-dist/src/main/resources/deps/netty-4.1.22.Final/LICENSE.jsr166y.txt
similarity index 100%
rename from bookkeeper-dist/src/main/resources/deps/netty-4.1.12.Final/LICENSE.jsr166y.txt
rename to bookkeeper-dist/src/main/resources/deps/netty-4.1.22.Final/LICENSE.jsr166y.txt
diff --git a/bookkeeper-dist/src/main/resources/deps/netty-4.1.12.Final/LICENSE.libdivsufsort.txt b/bookkeeper-dist/src/main/resources/deps/netty-4.1.22.Final/LICENSE.libdivsufsort.txt
similarity index 100%
rename from bookkeeper-dist/src/main/resources/deps/netty-4.1.12.Final/LICENSE.libdivsufsort.txt
rename to bookkeeper-dist/src/main/resources/deps/netty-4.1.22.Final/LICENSE.libdivsufsort.txt
diff --git a/bookkeeper-dist/src/main/resources/deps/netty-4.1.12.Final/LICENSE.protobuf.txt b/bookkeeper-dist/src/main/resources/deps/netty-4.1.22.Final/LICENSE.protobuf.txt
similarity index 100%
rename from bookkeeper-dist/src/main/resources/deps/netty-4.1.12.Final/LICENSE.protobuf.txt
rename to bookkeeper-dist/src/main/resources/deps/netty-4.1.22.Final/LICENSE.protobuf.txt
diff --git a/bookkeeper-dist/src/main/resources/deps/netty-4.1.12.Final/LICENSE.slf4j.txt b/bookkeeper-dist/src/main/resources/deps/netty-4.1.22.Final/LICENSE.slf4j.txt
similarity index 100%
rename from bookkeeper-dist/src/main/resources/deps/netty-4.1.12.Final/LICENSE.slf4j.txt
rename to bookkeeper-dist/src/main/resources/deps/netty-4.1.22.Final/LICENSE.slf4j.txt
diff --git a/bookkeeper-dist/src/main/resources/deps/netty-4.1.12.Final/LICENSE.webbit.txt b/bookkeeper-dist/src/main/resources/deps/netty-4.1.22.Final/LICENSE.webbit.txt
similarity index 100%
rename from bookkeeper-dist/src/main/resources/deps/netty-4.1.12.Final/LICENSE.webbit.txt
rename to bookkeeper-dist/src/main/resources/deps/netty-4.1.22.Final/LICENSE.webbit.txt
diff --git a/bookkeeper-dist/src/main/resources/deps/protobuf-3.3.1/LICENSE b/bookkeeper-dist/src/main/resources/deps/protobuf-3.3.1/LICENSE
deleted file mode 100644
index 2dcab42..0000000
--- a/bookkeeper-dist/src/main/resources/deps/protobuf-3.3.1/LICENSE
+++ /dev/null
@@ -1,32 +0,0 @@
-Copyright 2014, Google Inc.  All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-    * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
-    * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
-    * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Code generated by the Protocol Buffer compiler is owned by the owner
-of the input file used when generating it.  This code is not
-standalone and requires a support library to be linked with it.  This
-support library is itself covered by the above license.
diff --git a/bookkeeper-dist/src/main/resources/deps/protobuf-3.4.0/LICENSE b/bookkeeper-dist/src/main/resources/deps/protobuf-3.5.1/LICENSE
similarity index 100%
rename from bookkeeper-dist/src/main/resources/deps/protobuf-3.4.0/LICENSE
rename to bookkeeper-dist/src/main/resources/deps/protobuf-3.5.1/LICENSE
diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/BookieProtoEncodingTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/BookieProtoEncodingTest.java
index 6f9cc9a..a7f0c92 100644
--- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/BookieProtoEncodingTest.java
+++ b/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/BookieProtoEncodingTest.java
@@ -27,6 +27,7 @@ import static org.mockito.Mockito.when;
 
 import com.google.common.collect.Lists;
 import com.google.protobuf.ByteString;
+import com.google.protobuf.ExtensionRegistry;
 import com.google.protobuf.InvalidProtocolBufferException;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.UnpooledByteBufAllocator;
@@ -43,6 +44,7 @@ import org.apache.bookkeeper.proto.BookkeeperProtocol.BKPacketHeader;
 import org.apache.bookkeeper.proto.BookkeeperProtocol.OperationType;
 import org.apache.bookkeeper.proto.BookkeeperProtocol.ProtocolVersion;
 import org.apache.bookkeeper.proto.BookkeeperProtocol.StatusCode;
+import org.junit.Before;
 import org.junit.Test;
 
 /**
@@ -50,6 +52,13 @@ import org.junit.Test;
  */
 public class BookieProtoEncodingTest {
 
+    private ExtensionRegistry registry;
+
+    @Before
+    public void setup() {
+        this.registry = ExtensionRegistry.newInstance();
+    }
+
     @Test
     public void testV3ResponseDecoderNoFallback() throws Exception {
         AddResponse v2Resp = AddResponse.create(
@@ -79,10 +88,10 @@ public class BookieProtoEncodingTest {
                 return null;
         });
 
-        ResponseEnDeCoderPreV3 v2Encoder = new ResponseEnDeCoderPreV3(null);
-        ResponseEnDecoderV3 v3Encoder = new ResponseEnDecoderV3(null);
+        ResponseEnDeCoderPreV3 v2Encoder = new ResponseEnDeCoderPreV3(registry);
+        ResponseEnDecoderV3 v3Encoder = new ResponseEnDecoderV3(registry);
 
-        ResponseDecoder v3Decoder = new ResponseDecoder(null, false);
+        ResponseDecoder v3Decoder = new ResponseDecoder(registry, false);
         try {
             v3Decoder.channelRead(ctx,
                 v2Encoder.encode(v2Resp, UnpooledByteBufAllocator.DEFAULT)
@@ -101,8 +110,8 @@ public class BookieProtoEncodingTest {
 
     @Test(expected = IllegalStateException.class)
     public void testV2RequestDecoderThrowExceptionOnUnknownRequests() throws Exception {
-        RequestEnDeCoderPreV3 v2ReqEncoder = new RequestEnDeCoderPreV3(null);
-        RequestEnDecoderV3 v3ReqEncoder = new RequestEnDecoderV3(null);
+        RequestEnDeCoderPreV3 v2ReqEncoder = new RequestEnDeCoderPreV3(registry);
+        RequestEnDecoderV3 v3ReqEncoder = new RequestEnDecoderV3(registry);
 
         BookkeeperProtocol.Request v3Req = BookkeeperProtocol.Request.newBuilder()
             .setHeader(BKPacketHeader.newBuilder()
diff --git a/pom.xml b/pom.xml
index 715a2c2..8104b08 100644
--- a/pom.xml
+++ b/pom.xml
@@ -122,7 +122,7 @@
     <freebuilder.version>1.14.9</freebuilder.version>
     <google.code.version>3.0.2</google.code.version>
     <google.errorprone.version>2.1.2</google.errorprone.version>
-    <grpc.version>1.5.0</grpc.version>
+    <grpc.version>1.12.0</grpc.version>
     <guava.version>21.0</guava.version>
     <hadoop.version>2.7.3</hadoop.version>
     <hamcrest.version>1.3</hamcrest.version>
@@ -139,14 +139,14 @@
     <lombok.version>1.16.20</lombok.version>
     <lz4.version>1.3.0</lz4.version>
     <mockito.version>2.13.0</mockito.version>
-    <netty.version>4.1.12.Final</netty.version>
-    <netty-boringssl.version>2.0.3.Final</netty-boringssl.version>
+    <netty.version>4.1.22.Final</netty.version>
+    <netty-boringssl.version>2.0.7.Final</netty-boringssl.version>
     <ostrich.version>9.1.3</ostrich.version>
     <powermock.version>2.0.0-beta.5</powermock.version>
     <prometheus.version>0.0.21</prometheus.version>
     <datasketches.version>0.8.3</datasketches.version>
-    <protobuf.version>3.4.0</protobuf.version>
-    <protoc-gen-grpc-java.version>1.0.0</protoc-gen-grpc-java.version>
+    <protobuf.version>3.5.1</protobuf.version>
+    <protoc-gen-grpc-java.version>1.12.0</protoc-gen-grpc-java.version>
     <rocksdb.version>5.8.6</rocksdb.version>
     <shrinkwrap.version>3.0.1</shrinkwrap.version>
     <slf4j.version>1.7.25</slf4j.version>
@@ -362,12 +362,6 @@
         <groupId>io.grpc</groupId>
         <artifactId>grpc-all</artifactId>
         <version>${grpc.version}</version>
-        <exclusions>
-          <exclusion>
-            <groupId>com.google.errorprone</groupId>
-            <artifactId>error_prone_annotations</artifactId>
-          </exclusion>
-        </exclusions>
       </dependency>
 
       <!-- rocksdb dependencies -->
diff --git a/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/channel/StorageServerChannel.java b/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/channel/StorageServerChannel.java
index 7e1e022..d9e9388 100644
--- a/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/channel/StorageServerChannel.java
+++ b/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/channel/StorageServerChannel.java
@@ -74,6 +74,7 @@ public class StorageServerChannel implements AutoCloseable {
      * @param token    token used to access range server
      * @param usePlainText whether to plain text protocol or not
      */
+    @SuppressWarnings("deprecation")
     public StorageServerChannel(Endpoint endpoint,
                                 Optional<String> token,
                                 boolean usePlainText,
diff --git a/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/internal/LocationClientImpl.java b/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/internal/LocationClientImpl.java
index 95cae9a..db1c656 100644
--- a/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/internal/LocationClientImpl.java
+++ b/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/internal/LocationClientImpl.java
@@ -58,6 +58,7 @@ public class LocationClientImpl implements LocationClient {
     private final ManagedChannel channel;
     private final StorageContainerServiceFutureStub locationService;
 
+    @SuppressWarnings("deprecation")
     public LocationClientImpl(StorageClientSettings settings,
                               OrderedScheduler scheduler) {
         this.settings = settings;
diff --git a/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/utils/GrpcUtils.java b/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/utils/GrpcUtils.java
index cc7084a..e1d396a 100644
--- a/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/utils/GrpcUtils.java
+++ b/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/utils/GrpcUtils.java
@@ -20,11 +20,14 @@ package org.apache.bookkeeper.clients.utils;
 
 import static org.apache.bookkeeper.clients.utils.ClientConstants.TOKEN;
 
+import io.grpc.Attributes;
 import io.grpc.CallCredentials;
 import io.grpc.Metadata;
+import io.grpc.MethodDescriptor;
 import io.grpc.stub.AbstractStub;
 import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
 
 /**
  * Grpc related utils.
@@ -47,8 +50,19 @@ public final class GrpcUtils {
             Metadata metadata = new Metadata();
             Metadata.Key<String> tokenKey = Metadata.Key.of(TOKEN, Metadata.ASCII_STRING_MARSHALLER);
             metadata.put(tokenKey, t);
-            CallCredentials callCredentials = (method, attrs, appExecutor, applier) -> {
-                applier.apply(metadata);
+            CallCredentials callCredentials = new CallCredentials() {
+                @Override
+                public void applyRequestMetadata(MethodDescriptor<?, ?> method,
+                                                 Attributes attrs,
+                                                 Executor appExecutor,
+                                                 MetadataApplier applier) {
+                    applier.apply(metadata);
+                }
+
+                @Override
+                public void thisUsesUnstableApi() {
+                    // no-op;
+                }
             };
             return stub.withCallCredentials(callCredentials);
         }).orElse(stub);
diff --git a/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/proxy/PingPongServiceTestBase.java b/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/proxy/PingPongServiceTestBase.java
index ce3dcfd..6f7da16 100644
--- a/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/proxy/PingPongServiceTestBase.java
+++ b/stream/common/src/test/java/org/apache/bookkeeper/common/grpc/proxy/PingPongServiceTestBase.java
@@ -95,7 +95,7 @@ public abstract class PingPongServiceTestBase {
 
         if (useReverseProxy) {
             proxyChannel = InProcessChannelBuilder.forName(serverName)
-                .usePlaintext(false)
+                .usePlaintext()
                 .build();
 
             ProxyHandlerRegistry registry = ProxyHandlerRegistry.newBuilder()
@@ -113,7 +113,7 @@ public abstract class PingPongServiceTestBase {
         }
 
         clientChannel = InProcessChannelBuilder.forName(SERVICE_NAME)
-            .usePlaintext(false)
+            .usePlaintext()
             .build();
 
         client = PingPongServiceGrpc.newStub(clientChannel);

-- 
To stop receiving notification emails like this one, please contact
sijie@apache.org.

[bookkeeper] 03/09: [TABLE] mark TableClientTest & TableClientSimpleTest as FlakyTest

Posted by si...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sijie pushed a commit to branch branch-4.7
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git

commit ee7f13755cd4a32f632628de813bdd81949b6b6d
Author: Sijie Guo <si...@apache.org>
AuthorDate: Fri May 25 20:52:50 2018 -0700

    [TABLE] mark TableClientTest & TableClientSimpleTest as FlakyTest
    
    Descriptions of the changes in this PR:
    
    *Motivation*
    
    These two integration tests are flaky on shutting down. Mark them as `FlakyTest` to make CI stable while investigating the issue.
    
    *Changes*
    
    Move `FlakyTest` annotation from bookkeeper-server test jar to bookkeeper-common test jar. So it can be used across multiple modules.
    
    At the same time, remove redundant `FlakyTest` annotation at distributedlog-core module.
    
    Related Issue: #1440
    
    Author: Sijie Guo <si...@apache.org>
    
    Reviewers: Jia Zhai <None>
    
    This closes #1445 from sijie/mark_two_integration_tests_as_flaky
---
 .../common/testing}/annotations/FlakyTest.java          |  2 +-
 .../BookKeeperDiskSpaceWeightedLedgerPlacementTest.java |  2 +-
 .../bookkeeper/client/BookieDecommissionTest.java       |  2 +-
 .../common/annotations/DistributedLogAnnotations.java   |  6 ------
 stream/distributedlog/core/pom.xml                      |  7 +++++++
 .../apache/distributedlog/TestAsyncReaderWriter.java    |  3 ---
 .../org/apache/distributedlog/TestNonBlockingReads.java |  2 --
 .../org/apache/distributedlog/TestRollLogSegments.java  |  6 ------
 .../org/apache/distributedlog/TestZooKeeperClient.java  |  3 ---
 .../distributedlog/admin/TestDistributedLogAdmin.java   | 12 ++----------
 .../apache/distributedlog/bk/TestLedgerAllocator.java   | 17 +++--------------
 .../TestDynamicConfigurationFeatureProvider.java        | 12 ++----------
 tests/integration/cluster/pom.xml                       |  8 ++++++++
 .../integration/stream/StorageAdminClientTest.java      |  7 +++----
 .../tests/integration/stream/TableClientSimpleTest.java |  4 ++--
 .../tests/integration/stream/TableClientTest.java       |  4 ++--
 16 files changed, 32 insertions(+), 65 deletions(-)

diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/annotations/FlakyTest.java b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/annotations/FlakyTest.java
similarity index 95%
rename from bookkeeper-server/src/test/java/org/apache/bookkeeper/test/annotations/FlakyTest.java
rename to bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/annotations/FlakyTest.java
index 2890f35..8240cf2 100644
--- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/annotations/FlakyTest.java
+++ b/bookkeeper-common/src/test/java/org/apache/bookkeeper/common/testing/annotations/FlakyTest.java
@@ -15,7 +15,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.bookkeeper.test.annotations;
+package org.apache.bookkeeper.common.testing.annotations;
 
 import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperDiskSpaceWeightedLedgerPlacementTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperDiskSpaceWeightedLedgerPlacementTest.java
index 72f7c52..fec5dd8 100644
--- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperDiskSpaceWeightedLedgerPlacementTest.java
+++ b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperDiskSpaceWeightedLedgerPlacementTest.java
@@ -32,12 +32,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.bookkeeper.bookie.Bookie;
 import org.apache.bookkeeper.client.BookKeeper.DigestType;
+import org.apache.bookkeeper.common.testing.annotations.FlakyTest;
 import org.apache.bookkeeper.conf.ClientConfiguration;
 import org.apache.bookkeeper.conf.ServerConfiguration;
 import org.apache.bookkeeper.net.BookieSocketAddress;
 import org.apache.bookkeeper.proto.BookieServer;
 import org.apache.bookkeeper.test.BookKeeperClusterTestCase;
-import org.apache.bookkeeper.test.annotations.FlakyTest;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieDecommissionTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieDecommissionTest.java
index 0e4928e..b55a8c6 100644
--- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieDecommissionTest.java
+++ b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieDecommissionTest.java
@@ -29,10 +29,10 @@ import lombok.extern.slf4j.Slf4j;
 import org.apache.bookkeeper.bookie.Bookie;
 import org.apache.bookkeeper.client.BKException.BKIllegalOpException;
 import org.apache.bookkeeper.client.BookKeeper.DigestType;
+import org.apache.bookkeeper.common.testing.annotations.FlakyTest;
 import org.apache.bookkeeper.conf.ServerConfiguration;
 import org.apache.bookkeeper.meta.ZkLedgerUnderreplicationManager;
 import org.apache.bookkeeper.test.BookKeeperClusterTestCase;
-import org.apache.bookkeeper.test.annotations.FlakyTest;
 import org.junit.Test;
 
 /**
diff --git a/stream/distributedlog/common/src/main/java/org/apache/distributedlog/common/annotations/DistributedLogAnnotations.java b/stream/distributedlog/common/src/main/java/org/apache/distributedlog/common/annotations/DistributedLogAnnotations.java
index a5144b8..c1de7f6 100644
--- a/stream/distributedlog/common/src/main/java/org/apache/distributedlog/common/annotations/DistributedLogAnnotations.java
+++ b/stream/distributedlog/common/src/main/java/org/apache/distributedlog/common/annotations/DistributedLogAnnotations.java
@@ -22,12 +22,6 @@ package org.apache.distributedlog.common.annotations;
  */
 public class DistributedLogAnnotations {
     /**
-     * Annotation to identify flaky tests in DistributedLog.
-     * As and when we find that a test is flaky, we'll add this annotation to it for reference.
-     */
-    public @interface FlakyTest {}
-
-    /**
      * Annotation to specify the occurrence of a compression operation. These are CPU intensive
      * and should be avoided in low-latency paths.
      */
diff --git a/stream/distributedlog/core/pom.xml b/stream/distributedlog/core/pom.xml
index 22ad049..fd6356a 100644
--- a/stream/distributedlog/core/pom.xml
+++ b/stream/distributedlog/core/pom.xml
@@ -60,6 +60,13 @@
       <scope>test</scope>
     </dependency>
     <dependency>
+      <groupId>org.apache.bookkeeper</groupId>
+      <artifactId>bookkeeper-common</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>org.apache.distributedlog</groupId>
       <artifactId>distributedlog-common</artifactId>
       <version>${project.parent.version}</version>
diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestAsyncReaderWriter.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestAsyncReaderWriter.java
index 9c40834..75e22ac 100644
--- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestAsyncReaderWriter.java
+++ b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestAsyncReaderWriter.java
@@ -56,7 +56,6 @@ import org.apache.distributedlog.api.LogReader;
 import org.apache.distributedlog.api.LogWriter;
 import org.apache.distributedlog.api.namespace.Namespace;
 import org.apache.distributedlog.api.namespace.NamespaceBuilder;
-import org.apache.distributedlog.common.annotations.DistributedLogAnnotations;
 import org.apache.distributedlog.common.config.ConcurrentBaseConfiguration;
 import org.apache.distributedlog.common.config.ConcurrentConstConfiguration;
 import org.apache.distributedlog.config.DynamicDistributedLogConfiguration;
@@ -826,7 +825,6 @@ public class TestAsyncReaderWriter extends TestDistributedLogBase {
      * Test Case: starting reading when the streams don't exist.
      * {@link https://issues.apache.org/jira/browse/DL-42}
      */
-    @DistributedLogAnnotations.FlakyTest
     @Ignore
     @Test(timeout = 120000)
     public void testSimpleAsyncReadWriteStartEmptyFactory() throws Exception {
@@ -1505,7 +1503,6 @@ public class TestAsyncReaderWriter extends TestDistributedLogBase {
         dlm.close();
     }
 
-    @DistributedLogAnnotations.FlakyTest
     @Test(timeout = 60000)
     public void testAsyncReadMissingLogSegmentsNotification() throws Exception {
         String name = "distrlog-async-reader-missing-zk-notification";
diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestNonBlockingReads.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestNonBlockingReads.java
index 4b17a13..ef9f184 100644
--- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestNonBlockingReads.java
+++ b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestNonBlockingReads.java
@@ -30,7 +30,6 @@ import java.util.concurrent.ScheduledThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 import org.apache.distributedlog.api.DistributedLogManager;
 import org.apache.distributedlog.api.LogReader;
-import org.apache.distributedlog.common.annotations.DistributedLogAnnotations;
 import org.apache.distributedlog.exceptions.IdleReaderException;
 import org.apache.distributedlog.util.Utils;
 import org.junit.Assert;
@@ -42,7 +41,6 @@ import org.slf4j.LoggerFactory;
 /**
  * {@link https://issues.apache.org/jira/browse/DL-12}.
  */
-@DistributedLogAnnotations.FlakyTest
 @Ignore
 public class TestNonBlockingReads extends TestDistributedLogBase {
     static final Logger LOG = LoggerFactory.getLogger(TestNonBlockingReads.class);
diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestRollLogSegments.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestRollLogSegments.java
index 7a8d33c..a3a3f34 100644
--- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestRollLogSegments.java
+++ b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestRollLogSegments.java
@@ -33,7 +33,6 @@ import org.apache.bookkeeper.common.concurrent.FutureEventListener;
 import org.apache.bookkeeper.feature.SettableFeature;
 import org.apache.distributedlog.api.DistributedLogManager;
 import org.apache.distributedlog.api.LogReader;
-import org.apache.distributedlog.common.annotations.DistributedLogAnnotations.FlakyTest;
 import org.apache.distributedlog.feature.CoreFeatureKeys;
 import org.apache.distributedlog.impl.logsegment.BKLogSegmentEntryReader;
 import org.apache.distributedlog.util.FailpointUtils;
@@ -42,10 +41,6 @@ import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-
-
-
-
 /**
  * Test Cases for RollLogSegments.
  */
@@ -339,7 +334,6 @@ public class TestRollLogSegments extends TestDistributedLogBase {
         assertEquals(expectedReaderPosition, readPosition.getEntryId());
     }
 
-    @FlakyTest
     @Test(timeout = 60000)
     @SuppressWarnings("deprecation")
     public void testCaughtUpReaderOnLogSegmentRolling() throws Exception {
diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestZooKeeperClient.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestZooKeeperClient.java
index 0c8daad..022b028 100644
--- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestZooKeeperClient.java
+++ b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/TestZooKeeperClient.java
@@ -33,7 +33,6 @@ import org.apache.bookkeeper.stats.NullStatsLogger;
 import org.apache.bookkeeper.zookeeper.BoundExponentialBackoffRetryPolicy;
 import org.apache.distributedlog.ZooKeeperClient.Credentials;
 import org.apache.distributedlog.ZooKeeperClient.DigestCredentials;
-import org.apache.distributedlog.common.annotations.DistributedLogAnnotations;
 import org.apache.zookeeper.CreateMode;
 import org.apache.zookeeper.KeeperException;
 import org.apache.zookeeper.WatchedEvent;
@@ -265,7 +264,6 @@ public class TestZooKeeperClient extends ZooKeeperClusterTestCase {
     /**
      * {@link https://issues.apache.org/jira/browse/DL-34}.
      */
-    @DistributedLogAnnotations.FlakyTest
     @Ignore
     @Test(timeout = 60000)
     public void testAclAuthSpansExpiration() throws Exception {
@@ -290,7 +288,6 @@ public class TestZooKeeperClient extends ZooKeeperClusterTestCase {
     /**
      * {@link https://issues.apache.org/jira/browse/DL-34}.
      */
-    @DistributedLogAnnotations.FlakyTest
     @Ignore
     @Test(timeout = 60000)
     public void testAclAuthSpansExpirationNonRetryableClient() throws Exception {
diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/admin/TestDistributedLogAdmin.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/admin/TestDistributedLogAdmin.java
index f5cd75e..b48d002 100644
--- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/admin/TestDistributedLogAdmin.java
+++ b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/admin/TestDistributedLogAdmin.java
@@ -23,6 +23,7 @@ import static org.junit.Assert.fail;
 
 import java.net.URI;
 import java.util.concurrent.CompletableFuture;
+import org.apache.bookkeeper.common.testing.annotations.FlakyTest;
 import org.apache.distributedlog.DLMTestUtil;
 import org.apache.distributedlog.DLSN;
 import org.apache.distributedlog.DistributedLogConfiguration;
@@ -35,7 +36,6 @@ import org.apache.distributedlog.api.AsyncLogReader;
 import org.apache.distributedlog.api.DistributedLogManager;
 import org.apache.distributedlog.api.namespace.Namespace;
 import org.apache.distributedlog.api.namespace.NamespaceBuilder;
-import org.apache.distributedlog.common.annotations.DistributedLogAnnotations;
 import org.apache.distributedlog.exceptions.UnexpectedException;
 import org.apache.distributedlog.metadata.DryrunLogSegmentMetadataStoreUpdater;
 import org.apache.distributedlog.metadata.LogSegmentMetadataStoreUpdater;
@@ -44,12 +44,9 @@ import org.apache.zookeeper.CreateMode;
 import org.apache.zookeeper.ZooDefs;
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-
 /**
  * TestDistributedLogAdmin.
  */
@@ -73,12 +70,7 @@ public class TestDistributedLogAdmin extends TestDistributedLogBase {
         zooKeeperClient.close();
     }
 
-    /**
-     * {@link https://issues.apache.org/jira/browse/DL-44}.
-     */
-    @DistributedLogAnnotations.FlakyTest
-    @Ignore
-    @Test(timeout = 60000)
+    @FlakyTest("https://issues.apache.org/jira/browse/DL-44")
     @SuppressWarnings("deprecation")
     public void testChangeSequenceNumber() throws Exception {
         DistributedLogConfiguration confLocal = new DistributedLogConfiguration();
diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/bk/TestLedgerAllocator.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/bk/TestLedgerAllocator.java
index 0270a4a..1786fe4 100644
--- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/bk/TestLedgerAllocator.java
+++ b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/bk/TestLedgerAllocator.java
@@ -31,6 +31,7 @@ import org.apache.bookkeeper.client.BKException;
 import org.apache.bookkeeper.client.BookKeeper;
 import org.apache.bookkeeper.client.LedgerEntry;
 import org.apache.bookkeeper.client.LedgerHandle;
+import org.apache.bookkeeper.common.testing.annotations.FlakyTest;
 import org.apache.bookkeeper.versioning.LongVersion;
 import org.apache.bookkeeper.versioning.Versioned;
 import org.apache.distributedlog.BookKeeperClient;
@@ -41,7 +42,6 @@ import org.apache.distributedlog.TestZooKeeperClientBuilder;
 import org.apache.distributedlog.ZooKeeperClient;
 import org.apache.distributedlog.bk.SimpleLedgerAllocator.AllocationException;
 import org.apache.distributedlog.bk.SimpleLedgerAllocator.Phase;
-import org.apache.distributedlog.common.annotations.DistributedLogAnnotations;
 import org.apache.distributedlog.exceptions.ZKException;
 import org.apache.distributedlog.util.Transaction.OpListener;
 import org.apache.distributedlog.util.Utils;
@@ -54,7 +54,6 @@ import org.apache.zookeeper.ZooDefs;
 import org.apache.zookeeper.data.Stat;
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TestName;
@@ -125,12 +124,7 @@ public class TestLedgerAllocator extends TestDistributedLogBase {
         return Utils.ioResult(SimpleLedgerAllocator.of(allocationPath, null, newQuorumConfigProvider(conf), zkc, bkc));
     }
 
-    /**
-     * {@link https://issues.apache.org/jira/browse/DL-43}.
-     */
-    @DistributedLogAnnotations.FlakyTest
-    @Ignore
-    @Test(timeout = 60000)
+    @FlakyTest("https://issues.apache.org/jira/browse/DL-43")
     public void testAllocation() throws Exception {
         String allocationPath = "/allocation1";
         SimpleLedgerAllocator allocator = createAllocator(allocationPath);
@@ -310,12 +304,7 @@ public class TestLedgerAllocator extends TestDistributedLogBase {
                 dlConf.getBKDigestPW().getBytes(UTF_8));
     }
 
-    /**
-     * {@link https://issues.apache.org/jira/browse/DL-26}.
-     */
-    @DistributedLogAnnotations.FlakyTest
-    @Ignore
-    @Test(timeout = 60000)
+    @FlakyTest("https://issues.apache.org/jira/browse/DL-26")
     public void testCloseAllocatorAfterConfirm() throws Exception {
         String allocationPath = "/allocation2";
         SimpleLedgerAllocator allocator = createAllocator(allocationPath);
diff --git a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/feature/TestDynamicConfigurationFeatureProvider.java b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/feature/TestDynamicConfigurationFeatureProvider.java
index 536a6c0..e395345 100644
--- a/stream/distributedlog/core/src/test/java/org/apache/distributedlog/feature/TestDynamicConfigurationFeatureProvider.java
+++ b/stream/distributedlog/core/src/test/java/org/apache/distributedlog/feature/TestDynamicConfigurationFeatureProvider.java
@@ -21,16 +21,13 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import org.apache.bookkeeper.common.testing.annotations.FlakyTest;
 import org.apache.bookkeeper.feature.Feature;
 import org.apache.bookkeeper.stats.NullStatsLogger;
 import org.apache.distributedlog.DistributedLogConfiguration;
-import org.apache.distributedlog.common.annotations.DistributedLogAnnotations;
 import org.apache.distributedlog.common.config.PropertiesWriter;
-import org.junit.Ignore;
 import org.junit.Test;
 
-
-
 /**
  * Test case for dynamic configuration based feature provider.
  */
@@ -79,12 +76,7 @@ public class TestDynamicConfigurationFeatureProvider {
         provider.stop();
     }
 
-    /**
-     * {@link https://issues.apache.org/jira/browse/DL-40}.
-     */
-    @DistributedLogAnnotations.FlakyTest
-    @Ignore
-    @Test(timeout = 60000)
+    @FlakyTest("https://issues.apache.org/jira/browse/DL-40")
     public void testLoadFeaturesFromOverlay() throws Exception {
         PropertiesWriter writer = new PropertiesWriter();
         writer.setProperty("feature_1", "10000");
diff --git a/tests/integration/cluster/pom.xml b/tests/integration/cluster/pom.xml
index 422269a..b33b7ab 100644
--- a/tests/integration/cluster/pom.xml
+++ b/tests/integration/cluster/pom.xml
@@ -51,6 +51,14 @@
       <scope>test</scope>
     </dependency>
 
+    <dependency>
+      <groupId>org.apache.bookkeeper</groupId>
+      <artifactId>bookkeeper-common</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+
   </dependencies>
 
   <build>
diff --git a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/StorageAdminClientTest.java b/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/StorageAdminClientTest.java
index 569cf7c..15198a3 100644
--- a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/StorageAdminClientTest.java
+++ b/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/StorageAdminClientTest.java
@@ -32,7 +32,7 @@ import org.apache.bookkeeper.clients.exceptions.NamespaceNotFoundException;
 import org.apache.bookkeeper.clients.exceptions.StreamExistsException;
 import org.apache.bookkeeper.clients.exceptions.StreamNotFoundException;
 import org.apache.bookkeeper.common.concurrent.FutureUtils;
-import org.apache.bookkeeper.common.util.OrderedScheduler;
+import org.apache.bookkeeper.common.testing.annotations.FlakyTest;
 import org.apache.bookkeeper.stream.proto.NamespaceConfiguration;
 import org.apache.bookkeeper.stream.proto.NamespaceProperties;
 import org.apache.bookkeeper.stream.proto.StreamConfiguration;
@@ -42,7 +42,6 @@ import org.apache.bookkeeper.stream.proto.storage.StatusCode;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
-import org.junit.Test;
 import org.junit.rules.TestName;
 
 /**
@@ -67,7 +66,7 @@ public class StorageAdminClientTest extends StreamClusterTestBase {
         }
     }
 
-    @Test
+    @FlakyTest("https://github.com/apache/bookkeeper/issues/1440")
     public void testNamespaceAPI() throws Exception {
         // Create a namespace
         String nsName = testName.getMethodName();
@@ -123,7 +122,7 @@ public class StorageAdminClientTest extends StreamClusterTestBase {
         }
     }
 
-    @Test
+    @FlakyTest("https://github.com/apache/bookkeeper/issues/1440")
     public void testStreamAPI() throws Exception {
         // Create a namespace
         String nsName = testName.getMethodName() + "_ns";
diff --git a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/TableClientSimpleTest.java b/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/TableClientSimpleTest.java
index d1ff091..e88dfc3 100644
--- a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/TableClientSimpleTest.java
+++ b/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/TableClientSimpleTest.java
@@ -40,6 +40,7 @@ import org.apache.bookkeeper.api.kv.result.Code;
 import org.apache.bookkeeper.api.kv.result.KeyValue;
 import org.apache.bookkeeper.clients.admin.StorageAdminClient;
 import org.apache.bookkeeper.clients.config.StorageClientSettings;
+import org.apache.bookkeeper.common.testing.annotations.FlakyTest;
 import org.apache.bookkeeper.stream.proto.NamespaceConfiguration;
 import org.apache.bookkeeper.stream.proto.NamespaceProperties;
 import org.apache.bookkeeper.stream.proto.StreamConfiguration;
@@ -47,7 +48,6 @@ import org.apache.bookkeeper.stream.proto.StreamProperties;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
-import org.junit.Test;
 import org.junit.rules.TestName;
 
 /**
@@ -89,7 +89,7 @@ public class TableClientSimpleTest extends StreamClusterTestBase {
         return Unpooled.wrappedBuffer(String.format("test-val-%06d", i).getBytes(UTF_8));
     }
 
-    @Test
+    @FlakyTest("https://github.com/apache/bookkeeper/issues/1440")
     public void testTableSimpleAPI() throws Exception {
         // Create a namespace
         NamespaceConfiguration nsConf = NamespaceConfiguration.newBuilder()
diff --git a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/TableClientTest.java b/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/TableClientTest.java
index 0dff7fa..6a287da 100644
--- a/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/TableClientTest.java
+++ b/tests/integration/cluster/src/test/java/org/apache/bookkeeper/tests/integration/stream/TableClientTest.java
@@ -50,6 +50,7 @@ import org.apache.bookkeeper.api.kv.result.TxnResult;
 import org.apache.bookkeeper.clients.admin.StorageAdminClient;
 import org.apache.bookkeeper.clients.config.StorageClientSettings;
 import org.apache.bookkeeper.common.concurrent.FutureUtils;
+import org.apache.bookkeeper.common.testing.annotations.FlakyTest;
 import org.apache.bookkeeper.stream.proto.NamespaceConfiguration;
 import org.apache.bookkeeper.stream.proto.NamespaceProperties;
 import org.apache.bookkeeper.stream.proto.StreamConfiguration;
@@ -57,7 +58,6 @@ import org.apache.bookkeeper.stream.proto.StreamProperties;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
-import org.junit.Test;
 import org.junit.rules.TestName;
 
 /**
@@ -100,7 +100,7 @@ public class TableClientTest extends StreamClusterTestBase {
         return Unpooled.wrappedBuffer(String.format("test-val-%06d", i).getBytes(UTF_8));
     }
 
-    @Test
+    @FlakyTest("https://github.com/apache/bookkeeper/issues/1440")
     public void testTableAPI() throws Exception {
         // Create a namespace
         NamespaceConfiguration nsConf = NamespaceConfiguration.newBuilder()

-- 
To stop receiving notification emails like this one, please contact
sijie@apache.org.

[bookkeeper] 05/09: [TABLE SERVICE] use grpc reverse proxy to serve storage container requests

Posted by si...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sijie pushed a commit to branch branch-4.7
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git

commit 8e4c13b5e12d94a8a6ec921d6dc28a2b0ca4a0ca
Author: Sijie Guo <si...@apache.org>
AuthorDate: Mon May 28 18:29:09 2018 -0700

    [TABLE SERVICE] use grpc reverse proxy to serve storage container requests
    
    Descriptions of the changes in this PR:
    
    *Motivation*
    
    *Changes*
    
    **Client Changes**
    
    Changed `StorageContainerChannel` to add client interceptor to stamp storage container id into the the requests' metadata.
    
    **Server Changes**
    
    - moved the stream storage logic out of storage containers to a `service` package. the main logic will be kept in `RangeStoreService` and `RangeStoreServiceFactory`.
    - make the storage container logic for hosting `StorageContainerService`.
    - Each storage container will run an inprogress grpc server for serving the grpc services registered to the container and provide an `channel` for accessing those grpc service.
    - Changed the server to use reverse proxy for serving/proxying storage container requests.
    
    *NOTE*
    
    This change doesn't directly remove `StorageContainerRequest` and `StorageContainerResponse`.  It would be done in a subsequent change.
    
    Master Issue: #1205
    
    Author: Sijie Guo <si...@apache.org>
    
    Reviewers: Jia Zhai <None>
    
    This closes #1448 from sijie/storage_container_channel
---
 .../StorageContainerClientInterceptor.java         |   4 +-
 .../container/TestStorageContainerChannel.java     |  13 +-
 .../bookkeeper/common/util/ListenableFutures.java  |  10 +
 .../stream/protocol/ProtocolConstants.java         |   3 +
 .../bookkeeper/stream/server/StorageServer.java    |   6 +-
 .../bookkeeper/stream/server/grpc/GrpcServer.java  |  28 +-
 .../stream/server/grpc/GrpcServerSpec.java         |   4 +-
 .../server/grpc/GrpcStorageContainerService.java   |  10 +-
 .../stream/server/service/StorageService.java      |  16 +-
 .../stream/server/grpc/TestGrpcServer.java         |   6 +-
 ...{RangeStore.java => StorageContainerStore.java} |  15 +-
 .../storage/api/metadata/RangeStoreService.java    |   6 +
 .../stream/storage/api/sc/StorageContainer.java    |  12 +-
 ...Container.java => StorageContainerService.java} |  36 ++-
 .../api/sc/StorageContainerServiceFactory.java     |  39 +++
 .../api/service/RangeStoreServiceFactory.java      |  41 +++
 .../stream/storage/api/service/package-info.java   |  22 ++
 stream/storage/impl/pom.xml                        |   5 +
 ...lder.java => StorageContainerStoreBuilder.java} |  56 ++--
 .../stream/storage/impl/RangeStoreImpl.java        | 206 -------------
 .../storage/impl/StorageContainerStoreImpl.java    | 113 +++++++
 .../storage/impl/grpc/GrpcMetaRangeService.java    |   2 +-
 .../stream/storage/impl/grpc/GrpcServices.java     |  46 +++
 .../stream/storage/impl/sc/Channel404.java         |  80 +++++
 .../impl/sc/DefaultStorageContainerFactory.java    |  31 +-
 .../storage/impl/sc/StorageContainer404.java       |  63 ++++
 .../storage/impl/sc/StorageContainerImpl.java      | 336 ++++-----------------
 .../impl/sc/StorageContainerRegistryImpl.java      |   8 +-
 .../FailRequestRangeStoreService.java}             |  43 +--
 .../RangeStoreContainerServiceFactoryImpl.java     |  46 +++
 .../service/RangeStoreContainerServiceImpl.java    |  55 ++++
 .../impl/service/RangeStoreServiceFactoryImpl.java |  71 +++++
 .../RangeStoreServiceImpl.java}                    |  60 ++--
 .../stream/storage/impl/service/package-info.java  |  22 ++
 ....java => TestStorageContainerStoreBuilder.java} |  22 +-
 ...mpl.java => TestStorageContainerStoreImpl.java} | 244 ++++++++-------
 .../impl/grpc/TestGrpcMetaRangeService.java        |   8 +-
 .../impl/grpc/TestGrpcRootRangeService.java        |  26 +-
 .../storage/impl/grpc/TestGrpcTableService.java    |  20 +-
 .../sc/TestDefaultStorageContainerFactory.java     |  35 +--
 .../impl/sc/TestStorageContainerRegistryImpl.java  |  23 +-
 .../impl/sc/ZkStorageContainerManagerTest.java     |  15 +-
 .../RangeStoreServiceImplTest.java}                |  12 +-
 43 files changed, 1034 insertions(+), 885 deletions(-)

diff --git a/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/container/StorageContainerClientInterceptor.java b/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/container/StorageContainerClientInterceptor.java
index 284431e..1e1de08 100644
--- a/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/container/StorageContainerClientInterceptor.java
+++ b/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/container/StorageContainerClientInterceptor.java
@@ -18,6 +18,8 @@
 
 package org.apache.bookkeeper.clients.impl.container;
 
+import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.SC_ID_KEY;
+
 import io.grpc.CallOptions;
 import io.grpc.Channel;
 import io.grpc.ClientCall;
@@ -32,8 +34,6 @@ import org.apache.bookkeeper.common.grpc.netty.LongBinaryMarshaller;
  */
 public class StorageContainerClientInterceptor implements ClientInterceptor {
 
-    private static final String SC_ID_KEY = "SC_ID";
-
     private final long scId;
     private final Metadata.Key<Long> scIdKey;
 
diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/container/TestStorageContainerChannel.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/container/TestStorageContainerChannel.java
index 9d3869b..5623335 100644
--- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/container/TestStorageContainerChannel.java
+++ b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/container/TestStorageContainerChannel.java
@@ -26,6 +26,7 @@ import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -58,9 +59,9 @@ public class TestStorageContainerChannel extends GrpcClientTestBase {
     private OrderedScheduler scheduler;
     private final LocationClient locationClient = mock(LocationClient.class);
 
-    private StorageServerChannel mockChannel = mock(StorageServerChannel.class);
-    private StorageServerChannel mockChannel2 = mock(StorageServerChannel.class);
-    private StorageServerChannel mockChannel3 = mock(StorageServerChannel.class);
+    private StorageServerChannel mockChannel = newMockServerChannel();
+    private StorageServerChannel mockChannel2 = newMockServerChannel();
+    private StorageServerChannel mockChannel3 = newMockServerChannel();
     private final Endpoint endpoint = Endpoint.newBuilder()
         .setHostname("127.0.0.1")
         .setPort(8181)
@@ -106,6 +107,12 @@ public class TestStorageContainerChannel extends GrpcClientTestBase {
         }
     }
 
+    private StorageServerChannel newMockServerChannel() {
+        StorageServerChannel channel = mock(StorageServerChannel.class);
+        when(channel.intercept(anyLong())).thenReturn(channel);
+        return channel;
+    }
+
     private void ensureCallbackExecuted() throws Exception {
         final CountDownLatch latch = new CountDownLatch(1);
         scheduler.submit(() -> latch.countDown());
diff --git a/stream/common/src/main/java/org/apache/bookkeeper/common/util/ListenableFutures.java b/stream/common/src/main/java/org/apache/bookkeeper/common/util/ListenableFutures.java
index 586a457..29b5fa6 100644
--- a/stream/common/src/main/java/org/apache/bookkeeper/common/util/ListenableFutures.java
+++ b/stream/common/src/main/java/org/apache/bookkeeper/common/util/ListenableFutures.java
@@ -36,6 +36,16 @@ import lombok.NoArgsConstructor;
 public final class ListenableFutures {
 
     /**
+     * Convert a {@link ListenableFuture} to a {@link CompletableFuture}.
+     *
+     * @param listenableFuture listenable future to convert.
+     * @return the completable future.
+     */
+    public static <T> CompletableFuture<T> fromListenableFuture(ListenableFuture<T> listenableFuture) {
+        return fromListenableFuture(listenableFuture, Function.identity());
+    }
+
+    /**
      * Convert a {@link ListenableFuture} to a {@link CompletableFuture} and do a transformation.
      *
      * @param listenableFuture listenable future
diff --git a/stream/proto/src/main/java/org/apache/bookkeeper/stream/protocol/ProtocolConstants.java b/stream/proto/src/main/java/org/apache/bookkeeper/stream/protocol/ProtocolConstants.java
index 404ec56..0e6900c 100644
--- a/stream/proto/src/main/java/org/apache/bookkeeper/stream/protocol/ProtocolConstants.java
+++ b/stream/proto/src/main/java/org/apache/bookkeeper/stream/protocol/ProtocolConstants.java
@@ -18,6 +18,7 @@
 
 package org.apache.bookkeeper.stream.protocol;
 
+import io.grpc.Metadata;
 import org.apache.bookkeeper.stream.proto.FixedRangeSplitPolicy;
 import org.apache.bookkeeper.stream.proto.RangeKeyType;
 import org.apache.bookkeeper.stream.proto.RetentionPolicy;
@@ -107,4 +108,6 @@ public final class ProtocolConstants {
             .setSplitPolicy(DEFAULT_SPLIT_POLICY)
             .build();
 
+    // storage container request metadata key
+    public static final String SC_ID_KEY = "sc-id" + Metadata.BINARY_HEADER_SUFFIX;
 }
diff --git a/stream/server/src/main/java/org/apache/bookkeeper/stream/server/StorageServer.java b/stream/server/src/main/java/org/apache/bookkeeper/stream/server/StorageServer.java
index 94c8587..e0774de 100644
--- a/stream/server/src/main/java/org/apache/bookkeeper/stream/server/StorageServer.java
+++ b/stream/server/src/main/java/org/apache/bookkeeper/stream/server/StorageServer.java
@@ -48,7 +48,7 @@ import org.apache.bookkeeper.stream.server.service.RegistrationServiceProvider;
 import org.apache.bookkeeper.stream.server.service.RegistrationStateService;
 import org.apache.bookkeeper.stream.server.service.StatsProviderService;
 import org.apache.bookkeeper.stream.server.service.StorageService;
-import org.apache.bookkeeper.stream.storage.RangeStoreBuilder;
+import org.apache.bookkeeper.stream.storage.StorageContainerStoreBuilder;
 import org.apache.bookkeeper.stream.storage.StorageResources;
 import org.apache.bookkeeper.stream.storage.conf.StorageConfiguration;
 import org.apache.bookkeeper.stream.storage.impl.cluster.ClusterControllerImpl;
@@ -243,7 +243,7 @@ public class StorageServer {
             rootStatsLogger.scope("dlog"));
 
         // Create range (stream) store
-        RangeStoreBuilder rangeStoreBuilder = RangeStoreBuilder.newBuilder()
+        StorageContainerStoreBuilder storageContainerStoreBuilder = StorageContainerStoreBuilder.newBuilder()
             .withStatsLogger(rootStatsLogger.scope("storage"))
             .withStorageConfiguration(storageConf)
             // the storage resources shared across multiple components
@@ -281,7 +281,7 @@ public class StorageServer {
                     storageResources,
                     storageConf.getServeReadOnlyTables()));
         StorageService storageService = new StorageService(
-            storageConf, rangeStoreBuilder, rootStatsLogger.scope("storage"));
+            storageConf, storageContainerStoreBuilder, rootStatsLogger.scope("storage"));
 
         // Create gRPC server
         StatsLogger rpcStatsLogger = rootStatsLogger.scope("grpc");
diff --git a/stream/server/src/main/java/org/apache/bookkeeper/stream/server/grpc/GrpcServer.java b/stream/server/src/main/java/org/apache/bookkeeper/stream/server/grpc/GrpcServer.java
index ce95ccf..7a5f163 100644
--- a/stream/server/src/main/java/org/apache/bookkeeper/stream/server/grpc/GrpcServer.java
+++ b/stream/server/src/main/java/org/apache/bookkeeper/stream/server/grpc/GrpcServer.java
@@ -18,18 +18,18 @@ import com.google.common.annotations.VisibleForTesting;
 import io.grpc.HandlerRegistry;
 import io.grpc.Server;
 import io.grpc.ServerBuilder;
+import io.grpc.ServerServiceDefinition;
 import io.grpc.inprocess.InProcessServerBuilder;
 import java.io.IOException;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.bookkeeper.common.component.AbstractLifecycleComponent;
+import org.apache.bookkeeper.common.grpc.proxy.ProxyHandlerRegistry;
 import org.apache.bookkeeper.stats.StatsLogger;
 import org.apache.bookkeeper.stream.proto.common.Endpoint;
 import org.apache.bookkeeper.stream.server.conf.StorageServerConfiguration;
 import org.apache.bookkeeper.stream.server.exceptions.StorageServerRuntimeException;
-import org.apache.bookkeeper.stream.storage.api.RangeStore;
-import org.apache.bookkeeper.stream.storage.impl.grpc.GrpcMetaRangeService;
-import org.apache.bookkeeper.stream.storage.impl.grpc.GrpcRootRangeService;
-import org.apache.bookkeeper.stream.storage.impl.grpc.GrpcTableService;
+import org.apache.bookkeeper.stream.storage.api.StorageContainerStore;
+import org.apache.bookkeeper.stream.storage.impl.grpc.GrpcServices;
 
 /**
  * KeyRange Server.
@@ -50,15 +50,15 @@ public class GrpcServer extends AbstractLifecycleComponent<StorageServerConfigur
     private final Endpoint myEndpoint;
     private final Server grpcServer;
 
-    public GrpcServer(RangeStore rangeStore,
+    public GrpcServer(StorageContainerStore storageContainerStore,
                       StorageServerConfiguration conf,
                       Endpoint myEndpoint,
                       StatsLogger statsLogger) {
-        this(rangeStore, conf, myEndpoint, null, null, statsLogger);
+        this(storageContainerStore, conf, myEndpoint, null, null, statsLogger);
     }
 
     @VisibleForTesting
-    public GrpcServer(RangeStore rangeStore,
+    public GrpcServer(StorageContainerStore storageContainerStore,
                       StorageServerConfiguration conf,
                       Endpoint myEndpoint,
                       String localServerName,
@@ -75,12 +75,14 @@ public class GrpcServer extends AbstractLifecycleComponent<StorageServerConfigur
             }
             this.grpcServer = serverBuilder.build();
         } else {
-            this.grpcServer = ServerBuilder
-                .forPort(this.myEndpoint.getPort())
-                .addService(new GrpcRootRangeService(rangeStore))
-                .addService(new GrpcStorageContainerService(rangeStore))
-                .addService(new GrpcMetaRangeService(rangeStore))
-                .addService(new GrpcTableService(rangeStore))
+            ProxyHandlerRegistry.Builder proxyRegistryBuilder = ProxyHandlerRegistry.newBuilder()
+                .setChannelFinder(storageContainerStore);
+            for (ServerServiceDefinition definition : GrpcServices.create(null)) {
+                proxyRegistryBuilder = proxyRegistryBuilder.addService(definition);
+            }
+            this.grpcServer = ServerBuilder.forPort(this.myEndpoint.getPort())
+                .addService(new GrpcStorageContainerService(storageContainerStore))
+                .fallbackHandlerRegistry(proxyRegistryBuilder.build())
                 .build();
         }
     }
diff --git a/stream/server/src/main/java/org/apache/bookkeeper/stream/server/grpc/GrpcServerSpec.java b/stream/server/src/main/java/org/apache/bookkeeper/stream/server/grpc/GrpcServerSpec.java
index 5b77b02..ac177e5 100644
--- a/stream/server/src/main/java/org/apache/bookkeeper/stream/server/grpc/GrpcServerSpec.java
+++ b/stream/server/src/main/java/org/apache/bookkeeper/stream/server/grpc/GrpcServerSpec.java
@@ -23,7 +23,7 @@ import lombok.experimental.Accessors;
 import org.apache.bookkeeper.stats.StatsLogger;
 import org.apache.bookkeeper.stream.proto.common.Endpoint;
 import org.apache.bookkeeper.stream.server.conf.StorageServerConfiguration;
-import org.apache.bookkeeper.stream.storage.api.RangeStore;
+import org.apache.bookkeeper.stream.storage.api.StorageContainerStore;
 
 /**
  * Spec for building a grpc server.
@@ -39,7 +39,7 @@ public class GrpcServerSpec {
      *
      * @return store supplier for building grpc server.
      */
-    Supplier<RangeStore> storeSupplier;
+    Supplier<StorageContainerStore> storeSupplier;
 
     /**
      * Get the storage server configuration.
diff --git a/stream/server/src/main/java/org/apache/bookkeeper/stream/server/grpc/GrpcStorageContainerService.java b/stream/server/src/main/java/org/apache/bookkeeper/stream/server/grpc/GrpcStorageContainerService.java
index e750bfc..8b6a26a 100644
--- a/stream/server/src/main/java/org/apache/bookkeeper/stream/server/grpc/GrpcStorageContainerService.java
+++ b/stream/server/src/main/java/org/apache/bookkeeper/stream/server/grpc/GrpcStorageContainerService.java
@@ -23,7 +23,7 @@ import org.apache.bookkeeper.stream.proto.storage.OneStorageContainerEndpointRes
 import org.apache.bookkeeper.stream.proto.storage.StatusCode;
 import org.apache.bookkeeper.stream.proto.storage.StorageContainerEndpoint;
 import org.apache.bookkeeper.stream.proto.storage.StorageContainerServiceGrpc.StorageContainerServiceImplBase;
-import org.apache.bookkeeper.stream.storage.api.RangeStore;
+import org.apache.bookkeeper.stream.storage.api.StorageContainerStore;
 
 /**
  * Grpc based storage container service.
@@ -31,10 +31,10 @@ import org.apache.bookkeeper.stream.storage.api.RangeStore;
 @Slf4j
 class GrpcStorageContainerService extends StorageContainerServiceImplBase {
 
-    private final RangeStore rangeStore;
+    private final StorageContainerStore storageContainerStore;
 
-    GrpcStorageContainerService(RangeStore rangeStore) {
-        this.rangeStore = rangeStore;
+    GrpcStorageContainerService(StorageContainerStore storageContainerStore) {
+        this.storageContainerStore = storageContainerStore;
     }
 
     @Override
@@ -43,7 +43,7 @@ class GrpcStorageContainerService extends StorageContainerServiceImplBase {
         GetStorageContainerEndpointResponse.Builder responseBuilder = GetStorageContainerEndpointResponse.newBuilder()
             .setStatusCode(StatusCode.SUCCESS);
         for (int i = 0; i < request.getRequestsCount(); i++) {
-            Endpoint endpoint = rangeStore
+            Endpoint endpoint = storageContainerStore
                 .getRoutingService()
                 .getStorageContainer(request.getRequests(i).getStorageContainer());
             OneStorageContainerEndpointResponse.Builder oneRespBuilder;
diff --git a/stream/server/src/main/java/org/apache/bookkeeper/stream/server/service/StorageService.java b/stream/server/src/main/java/org/apache/bookkeeper/stream/server/service/StorageService.java
index bddd6c1..2ac1804 100644
--- a/stream/server/src/main/java/org/apache/bookkeeper/stream/server/service/StorageService.java
+++ b/stream/server/src/main/java/org/apache/bookkeeper/stream/server/service/StorageService.java
@@ -19,23 +19,23 @@ import java.util.function.Supplier;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.bookkeeper.common.component.AbstractLifecycleComponent;
 import org.apache.bookkeeper.stats.StatsLogger;
-import org.apache.bookkeeper.stream.storage.RangeStoreBuilder;
-import org.apache.bookkeeper.stream.storage.api.RangeStore;
+import org.apache.bookkeeper.stream.storage.StorageContainerStoreBuilder;
+import org.apache.bookkeeper.stream.storage.api.StorageContainerStore;
 import org.apache.bookkeeper.stream.storage.conf.StorageConfiguration;
 
 /**
- * Service to run the storage {@link RangeStore}.
+ * Service to run the storage {@link StorageContainerStore}.
  */
 @Slf4j
 public class StorageService
     extends AbstractLifecycleComponent<StorageConfiguration>
-    implements Supplier<RangeStore> {
+    implements Supplier<StorageContainerStore> {
 
-    private final RangeStoreBuilder storeBuilder;
-    private RangeStore store;
+    private final StorageContainerStoreBuilder storeBuilder;
+    private StorageContainerStore store;
 
     public StorageService(StorageConfiguration conf,
-                          RangeStoreBuilder storeBuilder,
+                          StorageContainerStoreBuilder storeBuilder,
                           StatsLogger statsLogger) {
         super("storage-service", conf, statsLogger);
         this.storeBuilder = storeBuilder;
@@ -58,7 +58,7 @@ public class StorageService
     }
 
     @Override
-    public RangeStore get() {
+    public StorageContainerStore get() {
         return store;
     }
 }
diff --git a/stream/server/src/test/java/org/apache/bookkeeper/stream/server/grpc/TestGrpcServer.java b/stream/server/src/test/java/org/apache/bookkeeper/stream/server/grpc/TestGrpcServer.java
index b05640a..4cfbea1 100644
--- a/stream/server/src/test/java/org/apache/bookkeeper/stream/server/grpc/TestGrpcServer.java
+++ b/stream/server/src/test/java/org/apache/bookkeeper/stream/server/grpc/TestGrpcServer.java
@@ -22,7 +22,7 @@ import io.grpc.util.MutableHandlerRegistry;
 import org.apache.bookkeeper.stats.NullStatsLogger;
 import org.apache.bookkeeper.stream.server.StorageServer;
 import org.apache.bookkeeper.stream.server.conf.StorageServerConfiguration;
-import org.apache.bookkeeper.stream.storage.impl.RangeStoreImpl;
+import org.apache.bookkeeper.stream.storage.impl.StorageContainerStoreImpl;
 import org.apache.commons.configuration.CompositeConfiguration;
 import org.junit.Rule;
 import org.junit.Test;
@@ -41,7 +41,7 @@ public class TestGrpcServer {
     @Test
     public void testCreateLocalServer() {
         GrpcServer server = new GrpcServer(
-            mock(RangeStoreImpl.class),
+            mock(StorageContainerStoreImpl.class),
             StorageServerConfiguration.of(compConf),
             null,
             name.getMethodName(),
@@ -55,7 +55,7 @@ public class TestGrpcServer {
     @Test
     public void testCreateBindServer() throws Exception {
         GrpcServer server = new GrpcServer(
-            mock(RangeStoreImpl.class),
+            mock(StorageContainerStoreImpl.class),
             StorageServerConfiguration.of(compConf),
             StorageServer.createLocalEndpoint(0, false),
             null,
diff --git a/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/RangeStore.java b/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/StorageContainerStore.java
similarity index 68%
rename from stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/RangeStore.java
rename to stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/StorageContainerStore.java
index 164275b..61ff588 100644
--- a/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/RangeStore.java
+++ b/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/StorageContainerStore.java
@@ -14,15 +14,15 @@
 
 package org.apache.bookkeeper.stream.storage.api;
 
-import java.util.concurrent.ScheduledExecutorService;
 import org.apache.bookkeeper.common.component.LifecycleComponent;
-import org.apache.bookkeeper.stream.storage.api.metadata.RangeStoreService;
+import org.apache.bookkeeper.common.grpc.proxy.ChannelFinder;
+import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerRegistry;
 import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerRoutingService;
 
 /**
- * The umbrella interface for accessing ranges (both metadata and data).
+ * The umbrella interface for accessing storage containers.
  */
-public interface RangeStore extends LifecycleComponent, RangeStoreService {
+public interface StorageContainerStore extends LifecycleComponent, ChannelFinder {
 
     /**
      * Get the routing service.
@@ -32,11 +32,10 @@ public interface RangeStore extends LifecycleComponent, RangeStoreService {
     StorageContainerRoutingService getRoutingService();
 
     /**
-     * Choose the executor for a given {@code key}.
+     * Get the container registry.
      *
-     * @param key submit key
-     * @return executor
+     * @return container registry.
      */
-    ScheduledExecutorService chooseExecutor(long key);
+    StorageContainerRegistry getRegistry();
 
 }
diff --git a/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/metadata/RangeStoreService.java b/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/metadata/RangeStoreService.java
index 94e63d3..2aeb317 100644
--- a/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/metadata/RangeStoreService.java
+++ b/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/metadata/RangeStoreService.java
@@ -13,6 +13,7 @@
  */
 package org.apache.bookkeeper.stream.storage.api.metadata;
 
+import java.util.concurrent.CompletableFuture;
 import org.apache.bookkeeper.stream.storage.api.kv.TableStore;
 
 /**
@@ -22,4 +23,9 @@ public interface RangeStoreService
     extends MetaRangeStore,
     RootRangeStore,
     TableStore {
+
+    CompletableFuture<Void> start();
+
+    CompletableFuture<Void> stop();
+
 }
diff --git a/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/sc/StorageContainer.java b/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/sc/StorageContainer.java
index 47855b0..83c5dcd 100644
--- a/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/sc/StorageContainer.java
+++ b/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/sc/StorageContainer.java
@@ -18,16 +18,15 @@
 
 package org.apache.bookkeeper.stream.storage.api.sc;
 
+import io.grpc.Channel;
 import java.util.concurrent.CompletableFuture;
-import org.apache.bookkeeper.stream.storage.api.metadata.RangeStoreService;
 
 /**
  * A {@code StorageContainer} is a service container that can encapsulate metadata and data operations.
  *
  * <p>A {@link StorageContainer} is typically implemented by replicated state machine backed by a log.
  */
-public interface StorageContainer
-    extends AutoCloseable, RangeStoreService {
+public interface StorageContainer extends AutoCloseable {
 
     /**
      * Get the storage container id.
@@ -37,6 +36,13 @@ public interface StorageContainer
     long getId();
 
     /**
+     * Get the grpc channel to interact with grpc services registered in this container.
+     *
+     * @return grpc channel.
+     */
+    Channel getChannel();
+
+    /**
      * Start the storage container.
      *
      * @return a future represents the result of starting a storage container.
diff --git a/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/sc/StorageContainer.java b/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/sc/StorageContainerService.java
similarity index 57%
copy from stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/sc/StorageContainer.java
copy to stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/sc/StorageContainerService.java
index 47855b0..7014a73 100644
--- a/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/sc/StorageContainer.java
+++ b/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/sc/StorageContainerService.java
@@ -7,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -18,41 +18,39 @@
 
 package org.apache.bookkeeper.stream.storage.api.sc;
 
+import io.grpc.ServerServiceDefinition;
+import java.util.Collection;
 import java.util.concurrent.CompletableFuture;
-import org.apache.bookkeeper.stream.storage.api.metadata.RangeStoreService;
 
 /**
- * A {@code StorageContainer} is a service container that can encapsulate metadata and data operations.
+ * Represents the service running within a container.
  *
- * <p>A {@link StorageContainer} is typically implemented by replicated state machine backed by a log.
+ * <p>The implementation implements their core business logic and the framework provides resources like tables/streams
+ * for it.
  */
-public interface StorageContainer
-    extends AutoCloseable, RangeStoreService {
+public interface StorageContainerService {
 
     /**
-     * Get the storage container id.
+     * Return the registered grpc services.
      *
-     * @return the storage container id.
+     * <p>The framework registers the grpc services in the container runtime. So the framework will know how to route
+     * the grpc requests to the actual grpc services.
+     * @return
      */
-    long getId();
+    Collection<ServerServiceDefinition> getRegisteredServices();
 
     /**
-     * Start the storage container.
+     * Start the storage container service.
      *
-     * @return a future represents the result of starting a storage container.
+     * @return a future represents the result of starting a storage container service.
      */
-    CompletableFuture<StorageContainer> start();
+    CompletableFuture<Void> start();
 
     /**
-     * Stop the storage container.
+     * Stop the storage container service.
      *
-     * @return a future represents the result of stopping a storage container.
+     * @return a future represents the result of stopping a storage container service.
      */
     CompletableFuture<Void> stop();
 
-    /**
-     * Close a storage container.
-     */
-    void close();
-
 }
diff --git a/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/sc/StorageContainerServiceFactory.java b/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/sc/StorageContainerServiceFactory.java
new file mode 100644
index 0000000..e15f7d7
--- /dev/null
+++ b/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/sc/StorageContainerServiceFactory.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.bookkeeper.stream.storage.api.sc;
+
+/**
+ * Factory to create storage container service.
+ */
+public interface StorageContainerServiceFactory extends AutoCloseable {
+
+    /**
+     * Create a storage container service with container id <tt>scId</tt>.
+     *
+     * @param scId storage container id
+     * @return storage container id
+     */
+    StorageContainerService createStorageContainerService(long scId);
+
+    /**
+     * {@inheritDoc}
+     */
+    void close();
+
+}
diff --git a/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/service/RangeStoreServiceFactory.java b/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/service/RangeStoreServiceFactory.java
new file mode 100644
index 0000000..075fd3e
--- /dev/null
+++ b/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/service/RangeStoreServiceFactory.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.bookkeeper.stream.storage.api.service;
+
+import org.apache.bookkeeper.stream.storage.api.metadata.RangeStoreService;
+
+/**
+ * Factory to create range store services.
+ */
+public interface RangeStoreServiceFactory extends AutoCloseable {
+
+    /**
+     * Create a range store service that will be launched at storage container <tt>scId</tt>.
+     *
+     * @param scId storage container to run range store service.
+     * @return range store service
+     */
+    RangeStoreService createService(long scId);
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    void close();
+}
diff --git a/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/service/package-info.java b/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/service/package-info.java
new file mode 100644
index 0000000..bb88ca2
--- /dev/null
+++ b/stream/storage/api/src/main/java/org/apache/bookkeeper/stream/storage/api/service/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Classes that provide stream storage service logic.
+ */
+package org.apache.bookkeeper.stream.storage.api.service;
\ No newline at end of file
diff --git a/stream/storage/impl/pom.xml b/stream/storage/impl/pom.xml
index b178fc7..4c656f4 100644
--- a/stream/storage/impl/pom.xml
+++ b/stream/storage/impl/pom.xml
@@ -60,6 +60,11 @@
       <classifier>tests</classifier>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.bookkeeper.tests</groupId>
+      <artifactId>stream-storage-tests-common</artifactId>
+      <version>${project.version}</version>
+    </dependency>
   </dependencies>
   <build>
     <plugins>
diff --git a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/RangeStoreBuilder.java b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/StorageContainerStoreBuilder.java
similarity index 72%
rename from stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/RangeStoreBuilder.java
rename to stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/StorageContainerStoreBuilder.java
index c03b374..9c96139 100644
--- a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/RangeStoreBuilder.java
+++ b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/StorageContainerStoreBuilder.java
@@ -20,20 +20,22 @@ import java.net.URI;
 import org.apache.bookkeeper.stats.NullStatsLogger;
 import org.apache.bookkeeper.stats.StatsLogger;
 import org.apache.bookkeeper.stream.protocol.util.StorageContainerPlacementPolicy;
-import org.apache.bookkeeper.stream.storage.api.RangeStore;
+import org.apache.bookkeeper.stream.storage.api.StorageContainerStore;
 import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerManagerFactory;
 import org.apache.bookkeeper.stream.storage.conf.StorageConfiguration;
-import org.apache.bookkeeper.stream.storage.impl.RangeStoreImpl;
+import org.apache.bookkeeper.stream.storage.impl.StorageContainerStoreImpl;
 import org.apache.bookkeeper.stream.storage.impl.sc.StorageContainerPlacementPolicyImpl;
+import org.apache.bookkeeper.stream.storage.impl.service.RangeStoreContainerServiceFactoryImpl;
+import org.apache.bookkeeper.stream.storage.impl.service.RangeStoreServiceFactoryImpl;
 import org.apache.bookkeeper.stream.storage.impl.store.MVCCStoreFactory;
 
 /**
  * Builder to build the storage component.
  */
-public final class RangeStoreBuilder {
+public final class StorageContainerStoreBuilder {
 
-    public static RangeStoreBuilder newBuilder() {
-        return new RangeStoreBuilder();
+    public static StorageContainerStoreBuilder newBuilder() {
+        return new StorageContainerStoreBuilder();
     }
 
     private StatsLogger statsLogger = NullStatsLogger.INSTANCE;
@@ -45,18 +47,7 @@ public final class RangeStoreBuilder {
     private MVCCStoreFactory mvccStoreFactory = null;
     private URI defaultBackendUri = null;
 
-    private RangeStoreBuilder() {
-    }
-
-    /**
-     * Build the range store with the provided {@code numStorageContainers}.
-     *
-     * @param numStorageContainers number of the storage containers.
-     * @return range store builder
-     */
-    public RangeStoreBuilder withNumStorageContainers(int numStorageContainers) {
-        this.placementPolicyFactory = () -> StorageContainerPlacementPolicyImpl.of(numStorageContainers);
-        return this;
+    private StorageContainerStoreBuilder() {
     }
 
     /**
@@ -65,7 +56,7 @@ public final class RangeStoreBuilder {
      * @param placementPolicyFactory placement policy factor to create placement policies.
      * @return range store builder.
      */
-    public RangeStoreBuilder withStorageContainerPlacementPolicyFactory(
+    public StorageContainerStoreBuilder withStorageContainerPlacementPolicyFactory(
         StorageContainerPlacementPolicy.Factory placementPolicyFactory) {
         this.placementPolicyFactory = placementPolicyFactory;
         return this;
@@ -77,7 +68,7 @@ public final class RangeStoreBuilder {
      * @param statsLogger stats logger for collecting stats.
      * @return range store builder;
      */
-    public RangeStoreBuilder withStatsLogger(StatsLogger statsLogger) {
+    public StorageContainerStoreBuilder withStatsLogger(StatsLogger statsLogger) {
         if (null == statsLogger) {
             return this;
         }
@@ -91,7 +82,7 @@ public final class RangeStoreBuilder {
      * @param storeConf storage configuration
      * @return range store builder
      */
-    public RangeStoreBuilder withStorageConfiguration(StorageConfiguration storeConf) {
+    public StorageContainerStoreBuilder withStorageConfiguration(StorageConfiguration storeConf) {
         this.storeConf = storeConf;
         return this;
     }
@@ -102,7 +93,7 @@ public final class RangeStoreBuilder {
      * @param scmFactory storage container manager factory.
      * @return range store builder
      */
-    public RangeStoreBuilder withStorageContainerManagerFactory(StorageContainerManagerFactory scmFactory) {
+    public StorageContainerStoreBuilder withStorageContainerManagerFactory(StorageContainerManagerFactory scmFactory) {
         this.scmFactory = scmFactory;
         return this;
     }
@@ -113,7 +104,7 @@ public final class RangeStoreBuilder {
      * @param resources storage resources.
      * @return range store builder.
      */
-    public RangeStoreBuilder withStorageResources(StorageResources resources) {
+    public StorageContainerStoreBuilder withStorageResources(StorageResources resources) {
         this.storeResources = resources;
         return this;
     }
@@ -124,7 +115,7 @@ public final class RangeStoreBuilder {
      * @param storeFactory factory to create range stores.
      * @return range store builder.
      */
-    public RangeStoreBuilder withRangeStoreFactory(MVCCStoreFactory storeFactory) {
+    public StorageContainerStoreBuilder withRangeStoreFactory(MVCCStoreFactory storeFactory) {
         this.mvccStoreFactory = storeFactory;
         return this;
     }
@@ -135,25 +126,32 @@ public final class RangeStoreBuilder {
      * @param uri uri for storing table ranges.
      * @return range store builder.
      */
-    public RangeStoreBuilder withDefaultBackendUri(URI uri) {
+    public StorageContainerStoreBuilder withDefaultBackendUri(URI uri) {
         this.defaultBackendUri = uri;
         return this;
     }
 
-    public RangeStore build() {
+    public StorageContainerStore build() {
         checkNotNull(scmFactory, "StorageContainerManagerFactory is not provided");
         checkNotNull(storeConf, "StorageConfiguration is not provided");
         checkNotNull(mvccStoreFactory, "MVCCStoreFactory is not provided");
         checkNotNull(defaultBackendUri, "Default backend uri is not provided");
         checkNotNull(placementPolicyFactory, "Storage Container Placement Policy Factory is not provided");
 
-        return new RangeStoreImpl(
+        RangeStoreServiceFactoryImpl serviceFactory = new RangeStoreServiceFactoryImpl(
             storeConf,
+            placementPolicyFactory.newPlacementPolicy(),
             storeResources.scheduler(),
-            scmFactory,
             mvccStoreFactory,
-            defaultBackendUri,
-            placementPolicyFactory,
+            defaultBackendUri);
+
+        RangeStoreContainerServiceFactoryImpl containerServiceFactory =
+            new RangeStoreContainerServiceFactoryImpl(serviceFactory);
+
+        return new StorageContainerStoreImpl(
+            storeConf,
+            scmFactory,
+            containerServiceFactory,
             statsLogger);
     }
 
diff --git a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/RangeStoreImpl.java b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/RangeStoreImpl.java
deleted file mode 100644
index f175a55..0000000
--- a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/RangeStoreImpl.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.bookkeeper.stream.storage.impl;
-
-import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.ROOT_STORAGE_CONTAINER_ID;
-
-import com.google.common.annotations.VisibleForTesting;
-import java.io.IOException;
-import java.net.URI;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ScheduledExecutorService;
-import org.apache.bookkeeper.common.component.AbstractLifecycleComponent;
-import org.apache.bookkeeper.common.util.OrderedScheduler;
-import org.apache.bookkeeper.common.util.SharedResourceManager;
-import org.apache.bookkeeper.common.util.SharedResourceManager.Resource;
-import org.apache.bookkeeper.stats.StatsLogger;
-import org.apache.bookkeeper.stream.proto.storage.CreateNamespaceRequest;
-import org.apache.bookkeeper.stream.proto.storage.CreateNamespaceResponse;
-import org.apache.bookkeeper.stream.proto.storage.CreateStreamRequest;
-import org.apache.bookkeeper.stream.proto.storage.CreateStreamResponse;
-import org.apache.bookkeeper.stream.proto.storage.DeleteNamespaceRequest;
-import org.apache.bookkeeper.stream.proto.storage.DeleteNamespaceResponse;
-import org.apache.bookkeeper.stream.proto.storage.DeleteStreamRequest;
-import org.apache.bookkeeper.stream.proto.storage.DeleteStreamResponse;
-import org.apache.bookkeeper.stream.proto.storage.GetNamespaceRequest;
-import org.apache.bookkeeper.stream.proto.storage.GetNamespaceResponse;
-import org.apache.bookkeeper.stream.proto.storage.GetStreamRequest;
-import org.apache.bookkeeper.stream.proto.storage.GetStreamResponse;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
-import org.apache.bookkeeper.stream.protocol.util.StorageContainerPlacementPolicy;
-import org.apache.bookkeeper.stream.storage.api.RangeStore;
-import org.apache.bookkeeper.stream.storage.api.sc.StorageContainer;
-import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerManager;
-import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerManagerFactory;
-import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerRoutingService;
-import org.apache.bookkeeper.stream.storage.conf.StorageConfiguration;
-import org.apache.bookkeeper.stream.storage.impl.sc.DefaultStorageContainerFactory;
-import org.apache.bookkeeper.stream.storage.impl.sc.StorageContainerRegistryImpl;
-import org.apache.bookkeeper.stream.storage.impl.store.MVCCStoreFactory;
-
-/**
- * KeyRange Service.
- */
-public class RangeStoreImpl
-    extends AbstractLifecycleComponent<StorageConfiguration>
-    implements RangeStore {
-
-    private final Resource<OrderedScheduler> schedulerResource;
-    private final OrderedScheduler scheduler;
-    private final StorageContainerManagerFactory scmFactory;
-    private final StorageContainerRegistryImpl scRegistry;
-    private final StorageContainerManager scManager;
-    private final MVCCStoreFactory storeFactory;
-
-    public RangeStoreImpl(StorageConfiguration conf,
-                          Resource<OrderedScheduler> schedulerResource,
-                          StorageContainerManagerFactory factory,
-                          MVCCStoreFactory mvccStoreFactory,
-                          URI defaultBackendUri,
-                          StorageContainerPlacementPolicy.Factory placementPolicyFactory,
-                          StatsLogger statsLogger) {
-        super("range-service", conf, statsLogger);
-        this.schedulerResource = schedulerResource;
-        this.scheduler = SharedResourceManager.shared().get(schedulerResource);
-        this.scmFactory = factory;
-        this.storeFactory = mvccStoreFactory;
-        StorageContainerPlacementPolicy placementPolicy = placementPolicyFactory.newPlacementPolicy();
-        this.scRegistry = new StorageContainerRegistryImpl(
-            new DefaultStorageContainerFactory(
-                conf,
-                placementPolicy,
-                scheduler,
-                storeFactory,
-                defaultBackendUri),
-            scheduler);
-        this.scManager = scmFactory.create(conf, scRegistry);
-    }
-
-    @Override
-    public ScheduledExecutorService chooseExecutor(long key) {
-        return this.scheduler.chooseThread(key);
-    }
-
-    @VisibleForTesting
-    StorageContainerRegistryImpl getRegistry() {
-        return this.scRegistry;
-    }
-
-    @Override
-    public StorageContainerRoutingService getRoutingService() {
-        return this.scManager;
-    }
-
-    //
-    // Lifecycle management
-    //
-
-    @Override
-    protected void doStart() {
-        this.scManager.start();
-    }
-
-    @Override
-    protected void doStop() {
-        this.scManager.stop();
-        this.scRegistry.close();
-    }
-
-    @Override
-    protected void doClose() throws IOException {
-        this.scManager.close();
-        // stop the core scheduler
-        SharedResourceManager.shared().release(
-            schedulerResource,
-            scheduler);
-    }
-
-    private StorageContainer getStorageContainer(long scId) {
-        return scRegistry.getStorageContainer(scId);
-    }
-
-    //
-    // Root Range Service
-    //
-
-    @Override
-    public CompletableFuture<CreateNamespaceResponse> createNamespace(CreateNamespaceRequest request) {
-        return getStorageContainer(ROOT_STORAGE_CONTAINER_ID).createNamespace(request);
-    }
-
-    @Override
-    public CompletableFuture<DeleteNamespaceResponse> deleteNamespace(DeleteNamespaceRequest request) {
-        return getStorageContainer(ROOT_STORAGE_CONTAINER_ID).deleteNamespace(request);
-    }
-
-    @Override
-    public CompletableFuture<GetNamespaceResponse> getNamespace(GetNamespaceRequest request) {
-        return getStorageContainer(ROOT_STORAGE_CONTAINER_ID).getNamespace(request);
-    }
-
-    @Override
-    public CompletableFuture<CreateStreamResponse> createStream(CreateStreamRequest request) {
-        return getStorageContainer(ROOT_STORAGE_CONTAINER_ID).createStream(request);
-    }
-
-    @Override
-    public CompletableFuture<DeleteStreamResponse> deleteStream(DeleteStreamRequest request) {
-        return getStorageContainer(ROOT_STORAGE_CONTAINER_ID).deleteStream(request);
-    }
-
-    @Override
-    public CompletableFuture<GetStreamResponse> getStream(GetStreamRequest request) {
-        return getStorageContainer(ROOT_STORAGE_CONTAINER_ID).getStream(request);
-    }
-
-    //
-    // Stream Meta Range Service
-    //
-
-    @Override
-    public CompletableFuture<StorageContainerResponse> getActiveRanges(StorageContainerRequest request) {
-        return getStorageContainer(request.getScId()).getActiveRanges(request);
-    }
-
-    //
-    // Table Service
-    //
-
-    @Override
-    public CompletableFuture<StorageContainerResponse> range(StorageContainerRequest request) {
-        return getStorageContainer(request.getScId()).range(request);
-    }
-
-    @Override
-    public CompletableFuture<StorageContainerResponse> put(StorageContainerRequest request) {
-        return getStorageContainer(request.getScId()).put(request);
-    }
-
-    @Override
-    public CompletableFuture<StorageContainerResponse> delete(StorageContainerRequest request) {
-        return getStorageContainer(request.getScId()).delete(request);
-    }
-
-    @Override
-    public CompletableFuture<StorageContainerResponse> txn(StorageContainerRequest request) {
-        return getStorageContainer(request.getScId()).txn(request);
-    }
-
-    @Override
-    public CompletableFuture<StorageContainerResponse> incr(StorageContainerRequest request) {
-        return getStorageContainer(request.getScId()).incr(request);
-    }
-}
diff --git a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/StorageContainerStoreImpl.java b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/StorageContainerStoreImpl.java
new file mode 100644
index 0000000..56fcba2
--- /dev/null
+++ b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/StorageContainerStoreImpl.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.bookkeeper.stream.storage.impl;
+
+import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.INVALID_STORAGE_CONTAINER_ID;
+import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.SC_ID_KEY;
+
+import io.grpc.Channel;
+import io.grpc.Metadata;
+import io.grpc.ServerCall;
+import java.io.IOException;
+import org.apache.bookkeeper.common.component.AbstractLifecycleComponent;
+import org.apache.bookkeeper.common.grpc.netty.LongBinaryMarshaller;
+import org.apache.bookkeeper.stats.StatsLogger;
+import org.apache.bookkeeper.stream.storage.api.StorageContainerStore;
+import org.apache.bookkeeper.stream.storage.api.sc.StorageContainer;
+import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerManager;
+import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerManagerFactory;
+import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerRoutingService;
+import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerServiceFactory;
+import org.apache.bookkeeper.stream.storage.conf.StorageConfiguration;
+import org.apache.bookkeeper.stream.storage.impl.sc.DefaultStorageContainerFactory;
+import org.apache.bookkeeper.stream.storage.impl.sc.StorageContainerRegistryImpl;
+
+/**
+ * KeyRange Service.
+ */
+public class StorageContainerStoreImpl
+    extends AbstractLifecycleComponent<StorageConfiguration>
+    implements StorageContainerStore {
+
+    private final StorageContainerManagerFactory scmFactory;
+    private final StorageContainerRegistryImpl scRegistry;
+    private final StorageContainerManager scManager;
+    private final StorageContainerServiceFactory serviceFactory;
+    private final Metadata.Key<Long> scIdKey;
+
+    public StorageContainerStoreImpl(StorageConfiguration conf,
+                                     StorageContainerManagerFactory managerFactory,
+                                     StorageContainerServiceFactory serviceFactory,
+                                     StatsLogger statsLogger) {
+        super("range-service", conf, statsLogger);
+        this.scmFactory = managerFactory;
+        this.scRegistry = new StorageContainerRegistryImpl(
+            new DefaultStorageContainerFactory(serviceFactory));
+        this.scManager = scmFactory.create(conf, scRegistry);
+        this.serviceFactory = serviceFactory;
+        this.scIdKey = Metadata.Key.of(
+            SC_ID_KEY,
+            LongBinaryMarshaller.of());
+    }
+
+    @Override
+    public StorageContainerRegistryImpl getRegistry() {
+        return this.scRegistry;
+    }
+
+    @Override
+    public StorageContainerRoutingService getRoutingService() {
+        return this.scManager;
+    }
+
+    //
+    // Lifecycle management
+    //
+
+    @Override
+    protected void doStart() {
+        this.scManager.start();
+    }
+
+    @Override
+    protected void doStop() {
+        this.scManager.stop();
+        this.scRegistry.close();
+    }
+
+    @Override
+    protected void doClose() throws IOException {
+        this.scManager.close();
+        this.serviceFactory.close();
+    }
+
+    StorageContainer getStorageContainer(long scId) {
+        return scRegistry.getStorageContainer(scId);
+    }
+
+    //
+    // Utils for proxies
+    //
+
+    @Override
+    public Channel findChannel(ServerCall<?, ?> serverCall, Metadata headers) {
+        Long scId = headers.get(scIdKey);
+        if (null == scId) {
+            // use the invalid storage container id, so it will fail the request.
+            scId = INVALID_STORAGE_CONTAINER_ID;
+        }
+        return getStorageContainer(scId).getChannel();
+    }
+}
diff --git a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/grpc/GrpcMetaRangeService.java b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/grpc/GrpcMetaRangeService.java
index 1e4f681..2fe81e7 100644
--- a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/grpc/GrpcMetaRangeService.java
+++ b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/grpc/GrpcMetaRangeService.java
@@ -34,7 +34,7 @@ public class GrpcMetaRangeService extends MetaRangeServiceImplBase {
 
     private final RangeStoreService rangeStore;
 
-    public GrpcMetaRangeService(RangeStore service) {
+    public GrpcMetaRangeService(RangeStoreService service) {
         this.rangeStore = service;
         log.info("Created MetaRange service");
     }
diff --git a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/grpc/GrpcServices.java b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/grpc/GrpcServices.java
new file mode 100644
index 0000000..8cf8d26
--- /dev/null
+++ b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/grpc/GrpcServices.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.bookkeeper.stream.storage.impl.grpc;
+
+import com.google.common.collect.Lists;
+import io.grpc.ServerServiceDefinition;
+import java.util.Collection;
+import org.apache.bookkeeper.stream.storage.api.metadata.RangeStoreService;
+
+/**
+ * Define all the grpc services associated from a range store.
+ */
+public final class GrpcServices {
+
+    private GrpcServices() {}
+
+    /**
+     * Create the grpc services of a range store.
+     *
+     * @param store range store.
+     * @return the list of grpc services should be associated with the range store.
+     */
+    public static Collection<ServerServiceDefinition> create(RangeStoreService store) {
+        return Lists.newArrayList(
+            new GrpcRootRangeService(store).bindService(),
+            new GrpcMetaRangeService(store).bindService(),
+            new GrpcTableService(store).bindService());
+    }
+
+}
diff --git a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/Channel404.java b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/Channel404.java
new file mode 100644
index 0000000..4905aa8
--- /dev/null
+++ b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/Channel404.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.bookkeeper.stream.storage.impl.sc;
+
+import io.grpc.CallOptions;
+import io.grpc.Channel;
+import io.grpc.ClientCall;
+import io.grpc.Metadata;
+import io.grpc.MethodDescriptor;
+import io.grpc.Status;
+import javax.annotation.Nullable;
+
+/**
+ * A channel that always throws {@link Status#NOT_FOUND}.
+ */
+final class Channel404 extends Channel {
+
+    static Channel404 of() {
+        return INSTANCE;
+    }
+
+    private static final Channel404 INSTANCE = new Channel404();
+
+    private static final ClientCall<Object, Object> CALL404 = new ClientCall<Object, Object>() {
+        @Override
+        public void start(Listener<Object> responseListener, Metadata headers) {
+            responseListener.onClose(Status.NOT_FOUND, new Metadata());
+        }
+
+        @Override
+        public void request(int numMessages) {
+            // no-op
+        }
+
+        @Override
+        public void cancel(@Nullable String message, @Nullable Throwable cause) {
+            // no-op
+        }
+
+        @Override
+        public void halfClose() {
+            // no-op
+        }
+
+        @Override
+        public void sendMessage(Object message) {
+            // no-op
+        }
+    };
+
+    private Channel404() {}
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <RequestT, ResponseT> ClientCall<RequestT, ResponseT> newCall(
+        MethodDescriptor<RequestT, ResponseT> methodDescriptor, CallOptions callOptions) {
+        return (ClientCall<RequestT, ResponseT>) CALL404;
+    }
+
+    @Override
+    public String authority() {
+        return null;
+    }
+}
diff --git a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/DefaultStorageContainerFactory.java b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/DefaultStorageContainerFactory.java
index 9fbf595..2073c0b 100644
--- a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/DefaultStorageContainerFactory.java
+++ b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/DefaultStorageContainerFactory.java
@@ -14,45 +14,24 @@
 
 package org.apache.bookkeeper.stream.storage.impl.sc;
 
-import java.net.URI;
-import org.apache.bookkeeper.common.util.OrderedScheduler;
-import org.apache.bookkeeper.stream.protocol.util.StorageContainerPlacementPolicy;
 import org.apache.bookkeeper.stream.storage.api.sc.StorageContainer;
 import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerFactory;
-import org.apache.bookkeeper.stream.storage.conf.StorageConfiguration;
-import org.apache.bookkeeper.stream.storage.impl.store.MVCCStoreFactory;
+import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerServiceFactory;
 
 /**
  * The default storage container factory for creating {@link StorageContainer}s.
  */
 public class DefaultStorageContainerFactory implements StorageContainerFactory {
 
-    private final StorageConfiguration storageConf;
-    private final StorageContainerPlacementPolicy rangePlacementPolicy;
-    private final OrderedScheduler scheduler;
-    private final MVCCStoreFactory storeFactory;
-    private final URI defaultBackendUri;
+    private final StorageContainerServiceFactory serviceFactory;
 
-    public DefaultStorageContainerFactory(StorageConfiguration storageConf,
-                                          StorageContainerPlacementPolicy rangePlacementPolicy,
-                                          OrderedScheduler scheduler,
-                                          MVCCStoreFactory storeFactory,
-                                          URI defaultBackendUri) {
-        this.storageConf = storageConf;
-        this.rangePlacementPolicy = rangePlacementPolicy;
-        this.scheduler = scheduler;
-        this.storeFactory = storeFactory;
-        this.defaultBackendUri = defaultBackendUri;
+    public DefaultStorageContainerFactory(StorageContainerServiceFactory serviceFactory) {
+        this.serviceFactory = serviceFactory;
     }
 
     @Override
     public StorageContainer createStorageContainer(long scId) {
         return new StorageContainerImpl(
-            storageConf,
-            scId,
-            rangePlacementPolicy,
-            scheduler,
-            storeFactory,
-            defaultBackendUri);
+            serviceFactory, scId);
     }
 }
diff --git a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/StorageContainer404.java b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/StorageContainer404.java
new file mode 100644
index 0000000..1d87c41
--- /dev/null
+++ b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/StorageContainer404.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.bookkeeper.stream.storage.impl.sc;
+
+import io.grpc.Channel;
+import java.util.concurrent.CompletableFuture;
+import org.apache.bookkeeper.common.concurrent.FutureUtils;
+import org.apache.bookkeeper.stream.storage.api.sc.StorageContainer;
+
+/**
+ * A storage container that always responds {@link io.grpc.Status#NOT_FOUND}.
+ */
+final class StorageContainer404 implements StorageContainer {
+
+    static StorageContainer404 of() {
+        return INSTANCE;
+    }
+
+    private static final StorageContainer404 INSTANCE = new StorageContainer404();
+
+    private StorageContainer404() {}
+
+    @Override
+    public long getId() {
+        return -404;
+    }
+
+    @Override
+    public Channel getChannel() {
+        return Channel404.of();
+    }
+
+    @Override
+    public CompletableFuture<StorageContainer> start() {
+        return FutureUtils.value(this);
+    }
+
+    @Override
+    public CompletableFuture<Void> stop() {
+        return FutureUtils.Void();
+    }
+
+    @Override
+    public void close() {
+        // no-op
+    }
+}
diff --git a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/StorageContainerImpl.java b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/StorageContainerImpl.java
index 52fa060..4bdc801 100644
--- a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/StorageContainerImpl.java
+++ b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/StorageContainerImpl.java
@@ -18,123 +18,47 @@
 
 package org.apache.bookkeeper.stream.storage.impl.sc;
 
-import static com.google.common.base.Preconditions.checkArgument;
-import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_DELETE_REQ;
-import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_INCR_REQ;
-import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_PUT_REQ;
-import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_RANGE_REQ;
-import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_TXN_REQ;
-import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.CONTAINER_META_RANGE_ID;
-import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.CONTAINER_META_STREAM_ID;
-import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.ROOT_RANGE_ID;
-import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.ROOT_STORAGE_CONTAINER_ID;
-import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.ROOT_STREAM_ID;
-
-import com.google.common.collect.Lists;
-import java.net.URI;
-import java.util.List;
+import io.grpc.Channel;
+import io.grpc.ManagedChannel;
+import io.grpc.Server;
+import io.grpc.ServerServiceDefinition;
+import io.grpc.inprocess.InProcessChannelBuilder;
+import io.grpc.inprocess.InProcessServerBuilder;
+import java.io.IOException;
+import java.util.Collection;
 import java.util.concurrent.CompletableFuture;
-import lombok.AccessLevel;
-import lombok.Getter;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.bookkeeper.common.concurrent.FutureUtils;
-import org.apache.bookkeeper.common.util.OrderedScheduler;
-import org.apache.bookkeeper.stream.proto.kv.rpc.DeleteRangeRequest;
-import org.apache.bookkeeper.stream.proto.kv.rpc.IncrementRequest;
-import org.apache.bookkeeper.stream.proto.kv.rpc.PutRequest;
-import org.apache.bookkeeper.stream.proto.kv.rpc.RangeRequest;
-import org.apache.bookkeeper.stream.proto.kv.rpc.RoutingHeader;
-import org.apache.bookkeeper.stream.proto.kv.rpc.TxnRequest;
-import org.apache.bookkeeper.stream.proto.storage.CreateNamespaceRequest;
-import org.apache.bookkeeper.stream.proto.storage.CreateNamespaceResponse;
-import org.apache.bookkeeper.stream.proto.storage.CreateStreamRequest;
-import org.apache.bookkeeper.stream.proto.storage.CreateStreamResponse;
-import org.apache.bookkeeper.stream.proto.storage.DeleteNamespaceRequest;
-import org.apache.bookkeeper.stream.proto.storage.DeleteNamespaceResponse;
-import org.apache.bookkeeper.stream.proto.storage.DeleteStreamRequest;
-import org.apache.bookkeeper.stream.proto.storage.DeleteStreamResponse;
-import org.apache.bookkeeper.stream.proto.storage.GetNamespaceRequest;
-import org.apache.bookkeeper.stream.proto.storage.GetNamespaceResponse;
-import org.apache.bookkeeper.stream.proto.storage.GetStreamRequest;
-import org.apache.bookkeeper.stream.proto.storage.GetStreamResponse;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
-import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
-import org.apache.bookkeeper.stream.protocol.RangeId;
-import org.apache.bookkeeper.stream.protocol.util.StorageContainerPlacementPolicy;
-import org.apache.bookkeeper.stream.storage.api.kv.TableStore;
-import org.apache.bookkeeper.stream.storage.api.metadata.MetaRangeStore;
-import org.apache.bookkeeper.stream.storage.api.metadata.RootRangeStore;
 import org.apache.bookkeeper.stream.storage.api.sc.StorageContainer;
-import org.apache.bookkeeper.stream.storage.conf.StorageConfiguration;
-import org.apache.bookkeeper.stream.storage.impl.kv.TableStoreCache;
-import org.apache.bookkeeper.stream.storage.impl.kv.TableStoreFactory;
-import org.apache.bookkeeper.stream.storage.impl.kv.TableStoreImpl;
-import org.apache.bookkeeper.stream.storage.impl.metadata.MetaRangeStoreFactory;
-import org.apache.bookkeeper.stream.storage.impl.metadata.MetaRangeStoreImpl;
-import org.apache.bookkeeper.stream.storage.impl.metadata.RootRangeStoreFactory;
-import org.apache.bookkeeper.stream.storage.impl.metadata.RootRangeStoreImpl;
-import org.apache.bookkeeper.stream.storage.impl.store.MVCCStoreFactory;
+import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerService;
+import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerServiceFactory;
 
 /**
  * The default implementation of {@link StorageContainer}.
  */
 @Slf4j
-public class StorageContainerImpl
-    implements StorageContainer {
+class StorageContainerImpl implements StorageContainer {
 
+    private final String containerName;
+    private final StorageContainerService service;
     private final long scId;
+    private final Server grpcServer;
+    private volatile Channel channel = Channel404.of();
 
-    // store container that used for fail requests.
-    private final StorageContainer failRequestStorageContainer;
-    // store factory
-    private final MVCCStoreFactory storeFactory;
-    // storage container
-    @Getter(value = AccessLevel.PACKAGE)
-    private MetaRangeStore mgStore;
-    @Getter(value = AccessLevel.PACKAGE)
-    private final MetaRangeStoreFactory mrStoreFactory;
-    // root range
-    @Getter(value = AccessLevel.PACKAGE)
-    private RootRangeStore rootRange;
-    @Getter(value = AccessLevel.PACKAGE)
-    private final RootRangeStoreFactory rrStoreFactory;
-    // table range stores
-    @Getter(value = AccessLevel.PACKAGE)
-    private final TableStoreCache tableStoreCache;
-    @Getter(value = AccessLevel.PACKAGE)
-    private final TableStoreFactory tableStoreFactory;
-
-    public StorageContainerImpl(StorageConfiguration storageConf,
-                                long scId,
-                                StorageContainerPlacementPolicy rangePlacementPolicy,
-                                OrderedScheduler scheduler,
-                                MVCCStoreFactory storeFactory,
-                                URI defaultBackendUri) {
-        this(
-            scId,
-            scheduler,
-            storeFactory,
-            store -> new RootRangeStoreImpl(
-                defaultBackendUri, store, rangePlacementPolicy, scheduler.chooseThread(scId)),
-            store -> new MetaRangeStoreImpl(store, rangePlacementPolicy, scheduler.chooseThread(scId)),
-            store -> new TableStoreImpl(store));
+    StorageContainerImpl(StorageContainerServiceFactory serviceFactory, long scId) {
+        this.scId = scId;
+        this.service = serviceFactory.createStorageContainerService(scId);
+        this.containerName = "container-" + scId;
+        this.grpcServer = buildGrpcServer(containerName, service.getRegisteredServices());
     }
 
-    public StorageContainerImpl(long scId,
-                                OrderedScheduler scheduler,
-                                MVCCStoreFactory storeFactory,
-                                RootRangeStoreFactory rrStoreFactory,
-                                MetaRangeStoreFactory mrStoreFactory,
-                                TableStoreFactory tableStoreFactory) {
-        this.scId = scId;
-        this.failRequestStorageContainer = FailRequestStorageContainer.of(scheduler);
-        this.rootRange = failRequestStorageContainer;
-        this.mgStore = failRequestStorageContainer;
-        this.storeFactory = storeFactory;
-        this.rrStoreFactory = rrStoreFactory;
-        this.mrStoreFactory = mrStoreFactory;
-        this.tableStoreFactory = tableStoreFactory;
-        this.tableStoreCache = new TableStoreCache(storeFactory, tableStoreFactory);
+    private static Server buildGrpcServer(String serverName,
+                                          Collection<ServerServiceDefinition> services) {
+        InProcessServerBuilder builder = InProcessServerBuilder.forName(serverName);
+        services.forEach(service -> builder.addService(service));
+        return builder
+            .directExecutor()
+            .build();
     }
 
     //
@@ -146,42 +70,24 @@ public class StorageContainerImpl
         return scId;
     }
 
-    private CompletableFuture<Void> startRootRangeStore() {
-        if (ROOT_STORAGE_CONTAINER_ID != scId) {
-            return FutureUtils.Void();
-        }
-        return storeFactory.openStore(
-            ROOT_STORAGE_CONTAINER_ID,
-            ROOT_STREAM_ID,
-            ROOT_RANGE_ID
-        ).thenApply(store -> {
-            rootRange = rrStoreFactory.createStore(store);
-            return null;
-        });
-    }
-
-    private CompletableFuture<Void> startMetaRangeStore(long scId) {
-        return storeFactory.openStore(
-            scId,
-            CONTAINER_META_STREAM_ID,
-            CONTAINER_META_RANGE_ID
-        ).thenApply(store -> {
-            mgStore = mrStoreFactory.createStore(store);
-            return null;
-        });
-    }
-
     @Override
     public CompletableFuture<StorageContainer> start() {
         log.info("Starting storage container ({}) ...", getId());
 
-        List<CompletableFuture<Void>> futures = Lists.newArrayList(
-            startRootRangeStore(),
-            startMetaRangeStore(scId));
-
-        return FutureUtils.collect(futures).thenApply(ignored -> {
-            log.info("Successfully started storage container ({}).", getId());
-            return StorageContainerImpl.this;
+        return service.start().thenCompose(ignored -> {
+            try {
+                grpcServer.start();
+                log.info("Successfully started storage container ({}).", getId());
+
+                channel = InProcessChannelBuilder.forName(containerName)
+                    .usePlaintext()
+                    .directExecutor()
+                    .build();
+                return FutureUtils.value(StorageContainerImpl.this);
+            } catch (IOException e) {
+                log.error("Failed to start the grpc server for storage container ({})", getId(), e);
+                return FutureUtils.exception(e);
+            }
         });
     }
 
@@ -189,160 +95,40 @@ public class StorageContainerImpl
     public CompletableFuture<Void> stop() {
         log.info("Stopping storage container ({}) ...", getId());
 
-        return storeFactory.closeStores(scId).thenApply(ignored -> {
-            log.info("Successfully stopped storage container ({}).", getId());
-            return null;
-        });
-    }
+        Channel existingChannel = channel;
 
-    @Override
-    public void close() {
-        stop().join();
-    }
-
-    //
-    // Storage Container API
-    //
-
-    //
-    // Namespace API
-    //
-
-    @Override
-    public CompletableFuture<CreateNamespaceResponse> createNamespace(CreateNamespaceRequest request) {
-        return rootRange.createNamespace(request);
-    }
+        // set channel to 404
+        channel = Channel404.of();
 
-    @Override
-    public CompletableFuture<DeleteNamespaceResponse> deleteNamespace(DeleteNamespaceRequest request) {
-        return rootRange.deleteNamespace(request);
-    }
-
-    @Override
-    public CompletableFuture<GetNamespaceResponse> getNamespace(GetNamespaceRequest request) {
-        return rootRange.getNamespace(request);
-    }
-
-    //
-    // Stream API.
-    //
-
-    @Override
-    public CompletableFuture<CreateStreamResponse> createStream(CreateStreamRequest request) {
-        return rootRange.createStream(request);
-    }
-
-    @Override
-    public CompletableFuture<DeleteStreamResponse> deleteStream(DeleteStreamRequest request) {
-        return rootRange.deleteStream(request);
-    }
+        if (null != existingChannel) {
+            if (existingChannel instanceof ManagedChannel) {
+                ((ManagedChannel) existingChannel).shutdown();
+            }
+        }
 
-    @Override
-    public CompletableFuture<GetStreamResponse> getStream(GetStreamRequest request) {
-        return rootRange.getStream(request);
-    }
+        if (null != grpcServer) {
+            grpcServer.shutdown();
+        }
 
-    //
-    // Stream Meta Range API.
-    //
+        return service.stop().thenApply(ignored -> {
 
-    @Override
-    public CompletableFuture<StorageContainerResponse> getActiveRanges(StorageContainerRequest request) {
-        return mgStore.getActiveRanges(request);
+            log.info("Successfully stopped storage container ({}).", getId());
+            return null;
+        });
     }
 
     //
-    // Table API
+    // Grpc
     //
 
-
-    @Override
-    public CompletableFuture<StorageContainerResponse> range(StorageContainerRequest request) {
-        checkArgument(KV_RANGE_REQ == request.getRequestCase());
-
-        long scId = request.getScId();
-        RangeRequest rr = request.getKvRangeReq();
-        RoutingHeader header = rr.getHeader();
-
-        RangeId rid = RangeId.of(header.getStreamId(), header.getRangeId());
-        TableStore store = tableStoreCache.getTableStore(rid);
-        if (null != store) {
-            return store.range(request);
-        } else {
-            return tableStoreCache.openTableStore(scId, rid)
-                .thenCompose(s -> s.range(request));
-        }
-    }
-
-    @Override
-    public CompletableFuture<StorageContainerResponse> put(StorageContainerRequest request) {
-        checkArgument(KV_PUT_REQ == request.getRequestCase());
-
-        long scId = request.getScId();
-        PutRequest rr = request.getKvPutReq();
-        RoutingHeader header = rr.getHeader();
-
-        RangeId rid = RangeId.of(header.getStreamId(), header.getRangeId());
-        TableStore store = tableStoreCache.getTableStore(rid);
-        if (null != store) {
-            return store.put(request);
-        } else {
-            return tableStoreCache.openTableStore(scId, rid)
-                .thenCompose(s -> s.put(request));
-        }
-    }
-
     @Override
-    public CompletableFuture<StorageContainerResponse> delete(StorageContainerRequest request) {
-        checkArgument(KV_DELETE_REQ == request.getRequestCase());
-
-        long scId = request.getScId();
-        DeleteRangeRequest rr = request.getKvDeleteReq();
-        RoutingHeader header = rr.getHeader();
-
-        RangeId rid = RangeId.of(header.getStreamId(), header.getRangeId());
-        TableStore store = tableStoreCache.getTableStore(rid);
-        if (null != store) {
-            return store.delete(request);
-        } else {
-            return tableStoreCache.openTableStore(scId, rid)
-                .thenCompose(s -> s.delete(request));
-        }
+    public Channel getChannel() {
+        return channel;
     }
 
     @Override
-    public CompletableFuture<StorageContainerResponse> txn(StorageContainerRequest request) {
-        checkArgument(KV_TXN_REQ == request.getRequestCase());
-
-        long scId = request.getScId();
-        TxnRequest rr = request.getKvTxnReq();
-        RoutingHeader header = rr.getHeader();
-
-        RangeId rid = RangeId.of(header.getStreamId(), header.getRangeId());
-        TableStore store = tableStoreCache.getTableStore(rid);
-        if (null != store) {
-            return store.txn(request);
-        } else {
-            return tableStoreCache.openTableStore(scId, rid)
-                .thenCompose(s -> s.txn(request));
-        }
+    public void close() {
+        stop().join();
     }
 
-    @Override
-    public CompletableFuture<StorageContainerResponse> incr(StorageContainerRequest request) {
-        checkArgument(KV_INCR_REQ == request.getRequestCase());
-
-        long scId = request.getScId();
-        IncrementRequest ir = request.getKvIncrReq();
-        RoutingHeader header = ir.getHeader();
-
-        RangeId rid = RangeId.of(header.getStreamId(), header.getRangeId());
-        TableStore store = tableStoreCache.getTableStore(rid);
-        if (null != store) {
-            return store.incr(request);
-        } else {
-            return tableStoreCache.openTableStore(scId, rid)
-                .thenCompose(s -> s.incr(request));
-        }
-    }
 }
diff --git a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/StorageContainerRegistryImpl.java b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/StorageContainerRegistryImpl.java
index 4499801..48330b7 100644
--- a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/StorageContainerRegistryImpl.java
+++ b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/StorageContainerRegistryImpl.java
@@ -22,7 +22,6 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.bookkeeper.common.concurrent.FutureUtils;
 import org.apache.bookkeeper.common.exceptions.ObjectClosedException;
-import org.apache.bookkeeper.common.util.OrderedScheduler;
 import org.apache.bookkeeper.stream.storage.api.sc.StorageContainer;
 import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerFactory;
 import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerRegistry;
@@ -39,13 +38,10 @@ public class StorageContainerRegistryImpl implements StorageContainerRegistry {
     private final StorageContainerFactory scFactory;
     private final ConcurrentMap<Long, StorageContainer> containers;
     private final ReentrantReadWriteLock closeLock;
-    private final StorageContainer failRequestStorageContainer;
     private boolean closed = false;
 
-    public StorageContainerRegistryImpl(StorageContainerFactory factory,
-                                        OrderedScheduler scheduler) {
+    public StorageContainerRegistryImpl(StorageContainerFactory factory) {
         this.scFactory = factory;
-        this.failRequestStorageContainer = FailRequestStorageContainer.of(scheduler);
         this.containers = Maps.newConcurrentMap();
         this.closeLock = new ReentrantReadWriteLock();
     }
@@ -62,7 +58,7 @@ public class StorageContainerRegistryImpl implements StorageContainerRegistry {
 
     @Override
     public StorageContainer getStorageContainer(long storageContainerId) {
-        return containers.getOrDefault(storageContainerId, failRequestStorageContainer);
+        return containers.getOrDefault(storageContainerId, StorageContainer404.of());
     }
 
     @Override
diff --git a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/FailRequestStorageContainer.java b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/FailRequestRangeStoreService.java
similarity index 85%
rename from stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/FailRequestStorageContainer.java
rename to stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/FailRequestRangeStoreService.java
index 8217e89..e15b808 100644
--- a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/FailRequestStorageContainer.java
+++ b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/FailRequestRangeStoreService.java
@@ -7,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -16,9 +16,8 @@
  * limitations under the License.
  */
 
-package org.apache.bookkeeper.stream.storage.impl.sc;
+package org.apache.bookkeeper.stream.storage.impl.service;
 
-import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.INVALID_STORAGE_CONTAINER_ID;
 import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.ROOT_STORAGE_CONTAINER_ID;
 
 import io.grpc.Status;
@@ -40,49 +39,39 @@ import org.apache.bookkeeper.stream.proto.storage.GetStreamRequest;
 import org.apache.bookkeeper.stream.proto.storage.GetStreamResponse;
 import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
 import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
-import org.apache.bookkeeper.stream.storage.api.sc.StorageContainer;
+import org.apache.bookkeeper.stream.storage.api.metadata.RangeStoreService;
 
 /**
  * It is a single-ton implementation that fails all requests.
  */
-public final class FailRequestStorageContainer implements StorageContainer {
+final class FailRequestRangeStoreService implements RangeStoreService {
 
-    public static StorageContainer of(OrderedScheduler scheduler) {
-        return new FailRequestStorageContainer(scheduler);
+    static RangeStoreService of(OrderedScheduler scheduler) {
+        return new FailRequestRangeStoreService(scheduler);
     }
 
     private final OrderedScheduler scheduler;
 
-    private FailRequestStorageContainer(OrderedScheduler scheduler) {
+    private FailRequestRangeStoreService(OrderedScheduler scheduler) {
         this.scheduler = scheduler;
     }
 
-    @Override
-    public long getId() {
-        return INVALID_STORAGE_CONTAINER_ID;
+    private <T> CompletableFuture<T> failWrongGroupRequest(long scId) {
+        CompletableFuture<T> future = FutureUtils.createFuture();
+        scheduler.executeOrdered(scId, () -> {
+            future.completeExceptionally(new StatusRuntimeException(Status.NOT_FOUND));
+        });
+        return future;
     }
 
     @Override
-    public CompletableFuture<StorageContainer> start() {
-        return CompletableFuture.completedFuture(this);
+    public CompletableFuture<Void> start() {
+        return FutureUtils.Void();
     }
 
     @Override
     public CompletableFuture<Void> stop() {
-        return CompletableFuture.completedFuture(null);
-    }
-
-    @Override
-    public void close() {
-        // no-op
-    }
-
-    private <T> CompletableFuture<T> failWrongGroupRequest(long scId) {
-        CompletableFuture<T> future = FutureUtils.createFuture();
-        scheduler.executeOrdered(scId, () -> {
-            future.completeExceptionally(new StatusRuntimeException(Status.NOT_FOUND));
-        });
-        return future;
+        return FutureUtils.Void();
     }
 
     //
diff --git a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreContainerServiceFactoryImpl.java b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreContainerServiceFactoryImpl.java
new file mode 100644
index 0000000..77a7950
--- /dev/null
+++ b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreContainerServiceFactoryImpl.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.bookkeeper.stream.storage.impl.service;
+
+import org.apache.bookkeeper.stream.storage.api.sc.StorageContainer;
+import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerService;
+import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerServiceFactory;
+import org.apache.bookkeeper.stream.storage.api.service.RangeStoreServiceFactory;
+
+/**
+ * The default storage container factory for creating {@link StorageContainer}s.
+ */
+public class RangeStoreContainerServiceFactoryImpl implements StorageContainerServiceFactory {
+
+    private final RangeStoreServiceFactory serviceFactory;
+
+    public RangeStoreContainerServiceFactoryImpl(RangeStoreServiceFactory serviceFactory) {
+        this.serviceFactory = serviceFactory;
+    }
+
+    @Override
+    public StorageContainerService createStorageContainerService(long scId) {
+        return new RangeStoreContainerServiceImpl(serviceFactory.createService(scId));
+    }
+
+    @Override
+    public void close() {
+        serviceFactory.close();
+    }
+}
diff --git a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreContainerServiceImpl.java b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreContainerServiceImpl.java
new file mode 100644
index 0000000..8a8f6d3
--- /dev/null
+++ b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreContainerServiceImpl.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.bookkeeper.stream.storage.impl.service;
+
+import io.grpc.ServerServiceDefinition;
+import java.util.Collection;
+import java.util.concurrent.CompletableFuture;
+import org.apache.bookkeeper.stream.storage.api.metadata.RangeStoreService;
+import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerService;
+import org.apache.bookkeeper.stream.storage.impl.grpc.GrpcServices;
+
+/**
+ * Implement the range service that runs on one storage container.
+ */
+class RangeStoreContainerServiceImpl implements StorageContainerService {
+
+    private final RangeStoreService store;
+    private final Collection<ServerServiceDefinition> grpcServices;
+
+    RangeStoreContainerServiceImpl(RangeStoreService service) {
+        this.store = service;
+        this.grpcServices = GrpcServices.create(service);
+    }
+
+    @Override
+    public Collection<ServerServiceDefinition> getRegisteredServices() {
+        return grpcServices;
+    }
+
+    @Override
+    public CompletableFuture<Void> start() {
+        return store.start();
+    }
+
+    @Override
+    public CompletableFuture<Void> stop() {
+        return store.stop();
+    }
+}
diff --git a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreServiceFactoryImpl.java b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreServiceFactoryImpl.java
new file mode 100644
index 0000000..02dd8a3
--- /dev/null
+++ b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreServiceFactoryImpl.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.bookkeeper.stream.storage.impl.service;
+
+import java.net.URI;
+import org.apache.bookkeeper.common.util.OrderedScheduler;
+import org.apache.bookkeeper.common.util.SharedResourceManager;
+import org.apache.bookkeeper.common.util.SharedResourceManager.Resource;
+import org.apache.bookkeeper.stream.protocol.util.StorageContainerPlacementPolicy;
+import org.apache.bookkeeper.stream.storage.api.metadata.RangeStoreService;
+import org.apache.bookkeeper.stream.storage.api.service.RangeStoreServiceFactory;
+import org.apache.bookkeeper.stream.storage.conf.StorageConfiguration;
+import org.apache.bookkeeper.stream.storage.impl.store.MVCCStoreFactory;
+
+/**
+ * Default implementation of {@link RangeStoreServiceFactory}.
+ */
+public class RangeStoreServiceFactoryImpl implements RangeStoreServiceFactory {
+
+    private final StorageConfiguration storageConf;
+    private final StorageContainerPlacementPolicy rangePlacementPolicy;
+    private final Resource<OrderedScheduler> schedulerResource;
+    private final OrderedScheduler scheduler;
+    private final MVCCStoreFactory storeFactory;
+    private final URI defaultBackendUri;
+
+    public RangeStoreServiceFactoryImpl(StorageConfiguration storageConf,
+                                        StorageContainerPlacementPolicy rangePlacementPolicy,
+                                        Resource<OrderedScheduler> schedulerResource,
+                                        MVCCStoreFactory storeFactory,
+                                        URI defaultBackendUri) {
+        this.storageConf = storageConf;
+        this.rangePlacementPolicy = rangePlacementPolicy;
+        this.schedulerResource = schedulerResource;
+        this.scheduler = SharedResourceManager.shared().get(schedulerResource);
+        this.storeFactory = storeFactory;
+        this.defaultBackendUri = defaultBackendUri;
+    }
+
+    @Override
+    public RangeStoreService createService(long scId) {
+        return new RangeStoreServiceImpl(
+            storageConf,
+            scId,
+            rangePlacementPolicy,
+            scheduler,
+            storeFactory,
+            defaultBackendUri);
+    }
+
+    @Override
+    public void close() {
+        SharedResourceManager.shared().release(schedulerResource, scheduler);
+    }
+}
diff --git a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/StorageContainerImpl.java b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreServiceImpl.java
similarity index 86%
copy from stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/StorageContainerImpl.java
copy to stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreServiceImpl.java
index 52fa060..0304fc8 100644
--- a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/sc/StorageContainerImpl.java
+++ b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreServiceImpl.java
@@ -7,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -16,7 +16,7 @@
  * limitations under the License.
  */
 
-package org.apache.bookkeeper.stream.storage.impl.sc;
+package org.apache.bookkeeper.stream.storage.impl.service;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_DELETE_REQ;
@@ -63,8 +63,8 @@ import org.apache.bookkeeper.stream.protocol.RangeId;
 import org.apache.bookkeeper.stream.protocol.util.StorageContainerPlacementPolicy;
 import org.apache.bookkeeper.stream.storage.api.kv.TableStore;
 import org.apache.bookkeeper.stream.storage.api.metadata.MetaRangeStore;
+import org.apache.bookkeeper.stream.storage.api.metadata.RangeStoreService;
 import org.apache.bookkeeper.stream.storage.api.metadata.RootRangeStore;
-import org.apache.bookkeeper.stream.storage.api.sc.StorageContainer;
 import org.apache.bookkeeper.stream.storage.conf.StorageConfiguration;
 import org.apache.bookkeeper.stream.storage.impl.kv.TableStoreCache;
 import org.apache.bookkeeper.stream.storage.impl.kv.TableStoreFactory;
@@ -76,16 +76,13 @@ import org.apache.bookkeeper.stream.storage.impl.metadata.RootRangeStoreImpl;
 import org.apache.bookkeeper.stream.storage.impl.store.MVCCStoreFactory;
 
 /**
- * The default implementation of {@link StorageContainer}.
+ * The service implementation running in a storage container.
  */
 @Slf4j
-public class StorageContainerImpl
-    implements StorageContainer {
+class RangeStoreServiceImpl implements RangeStoreService, AutoCloseable {
 
     private final long scId;
 
-    // store container that used for fail requests.
-    private final StorageContainer failRequestStorageContainer;
     // store factory
     private final MVCCStoreFactory storeFactory;
     // storage container
@@ -104,12 +101,12 @@ public class StorageContainerImpl
     @Getter(value = AccessLevel.PACKAGE)
     private final TableStoreFactory tableStoreFactory;
 
-    public StorageContainerImpl(StorageConfiguration storageConf,
-                                long scId,
-                                StorageContainerPlacementPolicy rangePlacementPolicy,
-                                OrderedScheduler scheduler,
-                                MVCCStoreFactory storeFactory,
-                                URI defaultBackendUri) {
+    RangeStoreServiceImpl(StorageConfiguration storageConf,
+                          long scId,
+                          StorageContainerPlacementPolicy rangePlacementPolicy,
+                          OrderedScheduler scheduler,
+                          MVCCStoreFactory storeFactory,
+                          URI defaultBackendUri) {
         this(
             scId,
             scheduler,
@@ -120,14 +117,15 @@ public class StorageContainerImpl
             store -> new TableStoreImpl(store));
     }
 
-    public StorageContainerImpl(long scId,
-                                OrderedScheduler scheduler,
-                                MVCCStoreFactory storeFactory,
-                                RootRangeStoreFactory rrStoreFactory,
-                                MetaRangeStoreFactory mrStoreFactory,
-                                TableStoreFactory tableStoreFactory) {
+    RangeStoreServiceImpl(long scId,
+                          OrderedScheduler scheduler,
+                          MVCCStoreFactory storeFactory,
+                          RootRangeStoreFactory rrStoreFactory,
+                          MetaRangeStoreFactory mrStoreFactory,
+                          TableStoreFactory tableStoreFactory) {
         this.scId = scId;
-        this.failRequestStorageContainer = FailRequestStorageContainer.of(scheduler);
+        RangeStoreService failRequestStorageContainer =
+            FailRequestRangeStoreService.of(scheduler);
         this.rootRange = failRequestStorageContainer;
         this.mgStore = failRequestStorageContainer;
         this.storeFactory = storeFactory;
@@ -141,7 +139,6 @@ public class StorageContainerImpl
     // Services
     //
 
-    @Override
     public long getId() {
         return scId;
     }
@@ -171,28 +168,16 @@ public class StorageContainerImpl
         });
     }
 
-    @Override
-    public CompletableFuture<StorageContainer> start() {
-        log.info("Starting storage container ({}) ...", getId());
-
+    public CompletableFuture<Void> start() {
         List<CompletableFuture<Void>> futures = Lists.newArrayList(
             startRootRangeStore(),
             startMetaRangeStore(scId));
 
-        return FutureUtils.collect(futures).thenApply(ignored -> {
-            log.info("Successfully started storage container ({}).", getId());
-            return StorageContainerImpl.this;
-        });
+        return FutureUtils.collect(futures).thenApply(ignored -> null);
     }
 
-    @Override
     public CompletableFuture<Void> stop() {
-        log.info("Stopping storage container ({}) ...", getId());
-
-        return storeFactory.closeStores(scId).thenApply(ignored -> {
-            log.info("Successfully stopped storage container ({}).", getId());
-            return null;
-        });
+        return storeFactory.closeStores(scId);
     }
 
     @Override
@@ -345,4 +330,5 @@ public class StorageContainerImpl
                 .thenCompose(s -> s.incr(request));
         }
     }
+
 }
diff --git a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/package-info.java b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/package-info.java
new file mode 100644
index 0000000..68ad094
--- /dev/null
+++ b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/service/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Classes that actually implement the storage services.
+ */
+package org.apache.bookkeeper.stream.storage.impl.service;
\ No newline at end of file
diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/TestRangeStoreBuilder.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/TestStorageContainerStoreBuilder.java
similarity index 84%
rename from stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/TestRangeStoreBuilder.java
rename to stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/TestStorageContainerStoreBuilder.java
index 85d3ef0..3d3a0ad 100644
--- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/TestRangeStoreBuilder.java
+++ b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/TestStorageContainerStoreBuilder.java
@@ -18,18 +18,18 @@ import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 
 import java.net.URI;
-import org.apache.bookkeeper.stream.storage.api.RangeStore;
+import org.apache.bookkeeper.stream.storage.api.StorageContainerStore;
 import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerManagerFactory;
 import org.apache.bookkeeper.stream.storage.conf.StorageConfiguration;
-import org.apache.bookkeeper.stream.storage.impl.RangeStoreImpl;
+import org.apache.bookkeeper.stream.storage.impl.StorageContainerStoreImpl;
 import org.apache.bookkeeper.stream.storage.impl.store.MVCCStoreFactory;
 import org.junit.Before;
 import org.junit.Test;
 
 /**
- * Unit test for {@link RangeStoreBuilder}.
+ * Unit test for {@link StorageContainerStoreBuilder}.
  */
-public class TestRangeStoreBuilder {
+public class TestStorageContainerStoreBuilder {
 
     private MVCCStoreFactory storeFactory;
     private final URI uri = URI.create("distributedlog://127.0.0.1/stream/storage");
@@ -41,7 +41,7 @@ public class TestRangeStoreBuilder {
 
     @Test(expected = NullPointerException.class)
     public void testBuildNullConfiguration() {
-        RangeStoreBuilder.newBuilder()
+        StorageContainerStoreBuilder.newBuilder()
             .withStorageConfiguration(null)
             .withStorageContainerManagerFactory(mock(StorageContainerManagerFactory.class))
             .withStorageResources(StorageResources.create())
@@ -52,7 +52,7 @@ public class TestRangeStoreBuilder {
 
     @Test(expected = NullPointerException.class)
     public void testBuildNullResources() {
-        RangeStoreBuilder.newBuilder()
+        StorageContainerStoreBuilder.newBuilder()
             .withStorageConfiguration(mock(StorageConfiguration.class))
             .withStorageContainerManagerFactory(mock(StorageContainerManagerFactory.class))
             .withStorageResources(null)
@@ -63,7 +63,7 @@ public class TestRangeStoreBuilder {
 
     @Test(expected = NullPointerException.class)
     public void testBuildNullRGManagerFactory() {
-        RangeStoreBuilder.newBuilder()
+        StorageContainerStoreBuilder.newBuilder()
             .withStorageConfiguration(mock(StorageConfiguration.class))
             .withStorageContainerManagerFactory(null)
             .withStorageResources(StorageResources.create())
@@ -74,7 +74,7 @@ public class TestRangeStoreBuilder {
 
     @Test(expected = NullPointerException.class)
     public void testBuildNullStoreFactory() {
-        RangeStoreBuilder.newBuilder()
+        StorageContainerStoreBuilder.newBuilder()
             .withStorageConfiguration(mock(StorageConfiguration.class))
             .withStorageContainerManagerFactory(mock(StorageContainerManagerFactory.class))
             .withStorageResources(StorageResources.create())
@@ -85,7 +85,7 @@ public class TestRangeStoreBuilder {
 
     @Test(expected = NullPointerException.class)
     public void testBuildNullDefaultBackendUri() {
-        RangeStoreBuilder.newBuilder()
+        StorageContainerStoreBuilder.newBuilder()
             .withStorageConfiguration(mock(StorageConfiguration.class))
             .withStorageContainerManagerFactory(mock(StorageContainerManagerFactory.class))
             .withStorageResources(StorageResources.create())
@@ -96,14 +96,14 @@ public class TestRangeStoreBuilder {
 
     @Test
     public void testBuild() {
-        RangeStore rangeStore = RangeStoreBuilder.newBuilder()
+        StorageContainerStore storageContainerStore = StorageContainerStoreBuilder.newBuilder()
             .withStorageConfiguration(mock(StorageConfiguration.class))
             .withStorageContainerManagerFactory(mock(StorageContainerManagerFactory.class))
             .withStorageResources(StorageResources.create())
             .withRangeStoreFactory(storeFactory)
             .withDefaultBackendUri(uri)
             .build();
-        assertTrue(rangeStore instanceof RangeStoreImpl);
+        assertTrue(storageContainerStore instanceof StorageContainerStoreImpl);
     }
 
 }
diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/TestRangeStoreImpl.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/TestStorageContainerStoreImpl.java
similarity index 69%
rename from stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/TestRangeStoreImpl.java
rename to stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/TestStorageContainerStoreImpl.java
index ac4bb78..a269466 100644
--- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/TestRangeStoreImpl.java
+++ b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/TestStorageContainerStoreImpl.java
@@ -14,6 +14,7 @@
 
 package org.apache.bookkeeper.stream.storage.impl;
 
+import static org.apache.bookkeeper.common.util.ListenableFutures.fromListenableFuture;
 import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.DEFAULT_STREAM_CONF;
 import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.ROOT_STORAGE_CONTAINER_ID;
 import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.createCreateNamespaceRequest;
@@ -33,14 +34,24 @@ import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import com.google.protobuf.ByteString;
+import io.grpc.Channel;
+import io.grpc.ClientInterceptors;
+import io.grpc.ManagedChannel;
+import io.grpc.Server;
+import io.grpc.ServerServiceDefinition;
 import io.grpc.Status;
 import io.grpc.StatusRuntimeException;
-import java.net.URI;
+import io.grpc.inprocess.InProcessChannelBuilder;
+import io.grpc.inprocess.InProcessServerBuilder;
+import java.util.Collection;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.bookkeeper.clients.impl.container.StorageContainerClientInterceptor;
 import org.apache.bookkeeper.common.concurrent.FutureUtils;
+import org.apache.bookkeeper.common.grpc.proxy.ProxyHandlerRegistry;
 import org.apache.bookkeeper.statelib.api.mvcc.MVCCAsyncStore;
+import org.apache.bookkeeper.stats.NullStatsLogger;
 import org.apache.bookkeeper.stream.proto.NamespaceConfiguration;
 import org.apache.bookkeeper.stream.proto.StreamName;
 import org.apache.bookkeeper.stream.proto.StreamProperties;
@@ -65,14 +76,21 @@ import org.apache.bookkeeper.stream.proto.storage.GetNamespaceRequest;
 import org.apache.bookkeeper.stream.proto.storage.GetNamespaceResponse;
 import org.apache.bookkeeper.stream.proto.storage.GetStreamRequest;
 import org.apache.bookkeeper.stream.proto.storage.GetStreamResponse;
+import org.apache.bookkeeper.stream.proto.storage.MetaRangeServiceGrpc;
+import org.apache.bookkeeper.stream.proto.storage.MetaRangeServiceGrpc.MetaRangeServiceFutureStub;
+import org.apache.bookkeeper.stream.proto.storage.RootRangeServiceGrpc;
+import org.apache.bookkeeper.stream.proto.storage.RootRangeServiceGrpc.RootRangeServiceFutureStub;
 import org.apache.bookkeeper.stream.proto.storage.StatusCode;
 import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
 import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
-import org.apache.bookkeeper.stream.storage.RangeStoreBuilder;
-import org.apache.bookkeeper.stream.storage.StorageResources;
-import org.apache.bookkeeper.stream.storage.api.sc.StorageContainer;
+import org.apache.bookkeeper.stream.proto.storage.TableServiceGrpc;
+import org.apache.bookkeeper.stream.proto.storage.TableServiceGrpc.TableServiceFutureStub;
+import org.apache.bookkeeper.stream.storage.api.metadata.RangeStoreService;
+import org.apache.bookkeeper.stream.storage.api.service.RangeStoreServiceFactory;
 import org.apache.bookkeeper.stream.storage.conf.StorageConfiguration;
+import org.apache.bookkeeper.stream.storage.impl.grpc.GrpcServices;
 import org.apache.bookkeeper.stream.storage.impl.sc.LocalStorageContainerManager;
+import org.apache.bookkeeper.stream.storage.impl.service.RangeStoreContainerServiceFactoryImpl;
 import org.apache.bookkeeper.stream.storage.impl.store.MVCCStoreFactory;
 import org.apache.commons.configuration.CompositeConfiguration;
 import org.junit.After;
@@ -80,10 +98,10 @@ import org.junit.Before;
 import org.junit.Test;
 
 /**
- * Unit test of {@link RangeStoreImpl}.
+ * Unit test of {@link StorageContainerStoreImpl}.
  */
 @Slf4j
-public class TestRangeStoreImpl {
+public class TestStorageContainerStoreImpl {
 
     private static final StreamProperties streamProps = StreamProperties.newBuilder()
         .setStorageContainerId(System.currentTimeMillis())
@@ -115,8 +133,13 @@ public class TestRangeStoreImpl {
         NamespaceConfiguration.newBuilder()
             .setDefaultStreamConf(DEFAULT_STREAM_CONF)
             .build();
-    private StorageResources storageResources;
-    private RangeStoreImpl rangeStore;
+    private RangeStoreService mockRangeStoreService;
+    private StorageContainerStoreImpl rangeStore;
+    private Server server;
+    private Channel channel;
+    private TableServiceFutureStub tableService;
+    private RootRangeServiceFutureStub rootRangeService;
+    private MetaRangeServiceFutureStub metaRangeService;
 
     //
     // Utils for table api
@@ -196,8 +219,6 @@ public class TestRangeStoreImpl {
     @SuppressWarnings("unchecked")
     @Before
     public void setUp() throws Exception {
-        storageResources = StorageResources.create();
-
         Endpoint endpoint = createEndpoint("127.0.0.1", 0);
 
         // create the client manager
@@ -208,19 +229,61 @@ public class TestRangeStoreImpl {
         when(storeFactory.closeStores(anyLong()))
             .thenReturn(FutureUtils.Void());
 
-        rangeStore = (RangeStoreImpl) RangeStoreBuilder.newBuilder()
-            .withStorageConfiguration(storageConf)
-            .withStorageResources(storageResources)
-            .withStorageContainerManagerFactory((storeConf, rgRegistry)
-                -> new LocalStorageContainerManager(endpoint, storeConf, rgRegistry, 2))
-            .withRangeStoreFactory(storeFactory)
-            .withDefaultBackendUri(URI.create("distributedlog://127.0.0.1/stream/storage"))
-            .build();
+        RangeStoreServiceFactory rangeStoreServiceFactory = mock(RangeStoreServiceFactory.class);
+        mockRangeStoreService = mock(RangeStoreService.class);
+        when(mockRangeStoreService.start()).thenReturn(FutureUtils.Void());
+        when(mockRangeStoreService.stop()).thenReturn(FutureUtils.Void());
+        when(rangeStoreServiceFactory.createService(anyLong()))
+            .thenReturn(mockRangeStoreService);
+
+        rangeStore = new StorageContainerStoreImpl(
+            storageConf,
+            (storeConf, rgRegistry)
+                -> new LocalStorageContainerManager(endpoint, storeConf, rgRegistry, 2),
+            new RangeStoreContainerServiceFactoryImpl(rangeStoreServiceFactory),
+            NullStatsLogger.INSTANCE);
+
         rangeStore.start();
+
+        final String serverName = "test-server";
+
+        Collection<ServerServiceDefinition> grpcServices = GrpcServices.create(null);
+        ProxyHandlerRegistry.Builder registryBuilder = ProxyHandlerRegistry.newBuilder();
+        grpcServices.forEach(service -> registryBuilder.addService(service));
+        ProxyHandlerRegistry registry = registryBuilder
+            .setChannelFinder(rangeStore)
+            .build();
+        server = InProcessServerBuilder.forName(serverName)
+            .fallbackHandlerRegistry(registry)
+            .directExecutor()
+            .build()
+            .start();
+
+        channel = InProcessChannelBuilder.forName(serverName)
+            .usePlaintext()
+            .build();
+
+        // intercept the channel with storage container information.
+        channel = ClientInterceptors.intercept(
+            channel,
+            new StorageContainerClientInterceptor(0L));
+
+
+        tableService = TableServiceGrpc.newFutureStub(channel);
+        metaRangeService = MetaRangeServiceGrpc.newFutureStub(channel);
+        rootRangeService = RootRangeServiceGrpc.newFutureStub(channel);
     }
 
     @After
     public void tearDown() {
+        if (null != channel) {
+            if (channel instanceof ManagedChannel) {
+                ((ManagedChannel) channel).shutdown();
+            }
+        }
+        if (null != server) {
+            server.shutdown();
+        }
         if (null != rangeStore) {
             rangeStore.close();
         }
@@ -247,8 +310,8 @@ public class TestRangeStoreImpl {
         rangeStore.getRegistry().stopStorageContainer(ROOT_STORAGE_CONTAINER_ID).join();
 
         String colName = "test-create-namespace-no-root-storage-container-store";
-        verifyNotFoundException(
-            rangeStore.createNamespace(createCreateNamespaceRequest(colName, namespaceConf)),
+        verifyNotFoundException(fromListenableFuture(
+            rootRangeService.createNamespace(createCreateNamespaceRequest(colName, namespaceConf))),
             Status.NOT_FOUND);
     }
 
@@ -257,8 +320,8 @@ public class TestRangeStoreImpl {
         rangeStore.getRegistry().stopStorageContainer(ROOT_STORAGE_CONTAINER_ID).join();
 
         String colName = "test-delete-namespace-no-root-storage-container-store";
-        verifyNotFoundException(
-            rangeStore.deleteNamespace(createDeleteNamespaceRequest(colName)),
+        verifyNotFoundException(fromListenableFuture(
+            rootRangeService.deleteNamespace(createDeleteNamespaceRequest(colName))),
             Status.NOT_FOUND);
     }
 
@@ -267,8 +330,8 @@ public class TestRangeStoreImpl {
         rangeStore.getRegistry().stopStorageContainer(ROOT_STORAGE_CONTAINER_ID).join();
 
         String colName = "test-get-namespace-no-root-storage-container-store";
-        verifyNotFoundException(
-            rangeStore.getNamespace(createGetNamespaceRequest(colName)),
+        verifyNotFoundException(fromListenableFuture(
+            rootRangeService.getNamespace(createGetNamespaceRequest(colName))),
             Status.NOT_FOUND);
     }
 
@@ -276,41 +339,35 @@ public class TestRangeStoreImpl {
     public void testCreateNamespaceMockRootStorageContainerStore() throws Exception {
         String colName = "test-create-namespace-mock-root-storage-container-store";
 
-        StorageContainer scStore = mock(StorageContainer.class);
-        when(scStore.stop()).thenReturn(FutureUtils.value(null));
-        rangeStore.getRegistry().setStorageContainer(ROOT_STORAGE_CONTAINER_ID, scStore);
         CreateNamespaceResponse createResp = CreateNamespaceResponse.newBuilder()
             .setCode(StatusCode.NAMESPACE_EXISTS)
             .build();
         CreateNamespaceRequest request = createCreateNamespaceRequest(colName, namespaceConf);
 
-        when(scStore.createNamespace(request))
+        when(mockRangeStoreService.createNamespace(request))
             .thenReturn(CompletableFuture.completedFuture(createResp));
 
         CompletableFuture<CreateNamespaceResponse> createRespFuture =
-            rangeStore.createNamespace(request);
-        verify(scStore, times(1)).createNamespace(request);
+            fromListenableFuture(rootRangeService.createNamespace(request));
         assertTrue(createResp == createRespFuture.get());
+        verify(mockRangeStoreService, times(1)).createNamespace(request);
     }
 
     @Test
     public void testDeleteNamespaceMockRootStorageContainerStore() throws Exception {
         String colName = "test-delete-namespace-no-root-storage-container-store";
 
-        StorageContainer scStore = mock(StorageContainer.class);
-        when(scStore.stop()).thenReturn(FutureUtils.value(null));
-        rangeStore.getRegistry().setStorageContainer(ROOT_STORAGE_CONTAINER_ID, scStore);
         DeleteNamespaceResponse deleteResp = DeleteNamespaceResponse.newBuilder()
             .setCode(StatusCode.NAMESPACE_NOT_FOUND)
             .build();
         DeleteNamespaceRequest request = createDeleteNamespaceRequest(colName);
 
-        when(scStore.deleteNamespace(request))
+        when(mockRangeStoreService.deleteNamespace(request))
             .thenReturn(CompletableFuture.completedFuture(deleteResp));
 
         CompletableFuture<DeleteNamespaceResponse> deleteRespFuture =
-            rangeStore.deleteNamespace(request);
-        verify(scStore, times(1)).deleteNamespace(request);
+            fromListenableFuture(rootRangeService.deleteNamespace(request));
+        verify(mockRangeStoreService, times(1)).deleteNamespace(request);
         assertTrue(deleteResp == deleteRespFuture.get());
     }
 
@@ -318,20 +375,17 @@ public class TestRangeStoreImpl {
     public void testGetNamespaceMockRootStorageContainerStore() throws Exception {
         String colName = "test-get-namespace-no-root-storage-container-store";
 
-        StorageContainer scStore = mock(StorageContainer.class);
-        when(scStore.stop()).thenReturn(FutureUtils.value(null));
-        rangeStore.getRegistry().setStorageContainer(ROOT_STORAGE_CONTAINER_ID, scStore);
         GetNamespaceResponse getResp = GetNamespaceResponse.newBuilder()
             .setCode(StatusCode.NAMESPACE_NOT_FOUND)
             .build();
         GetNamespaceRequest request = createGetNamespaceRequest(colName);
 
-        when(scStore.getNamespace(request)).thenReturn(
+        when(mockRangeStoreService.getNamespace(request)).thenReturn(
             CompletableFuture.completedFuture(getResp));
 
         CompletableFuture<GetNamespaceResponse> getRespFuture =
-            rangeStore.getNamespace(request);
-        verify(scStore, times(1)).getNamespace(request);
+            fromListenableFuture(rootRangeService.getNamespace(request));
+        verify(mockRangeStoreService, times(1)).getNamespace(request);
         assertTrue(getResp == getRespFuture.get());
     }
 
@@ -345,8 +399,8 @@ public class TestRangeStoreImpl {
 
         String colName = "test-create-namespace-no-root-storage-container-store";
         String streamName = colName;
-        verifyNotFoundException(
-            rangeStore.createStream(createCreateStreamRequest(colName, streamName, DEFAULT_STREAM_CONF)),
+        verifyNotFoundException(fromListenableFuture(
+            rootRangeService.createStream(createCreateStreamRequest(colName, streamName, DEFAULT_STREAM_CONF))),
             Status.NOT_FOUND);
     }
 
@@ -356,8 +410,8 @@ public class TestRangeStoreImpl {
 
         String colName = "test-delete-namespace-no-root-storage-container-store";
         String streamName = colName;
-        verifyNotFoundException(
-            rangeStore.deleteStream(createDeleteStreamRequest(colName, streamName)),
+        verifyNotFoundException(fromListenableFuture(
+            rootRangeService.deleteStream(createDeleteStreamRequest(colName, streamName))),
             Status.NOT_FOUND);
     }
 
@@ -367,8 +421,8 @@ public class TestRangeStoreImpl {
 
         String colName = "test-get-namespace-no-root-storage-container-store";
         String streamName = colName;
-        verifyNotFoundException(
-            rangeStore.getStream(createGetStreamRequest(colName, streamName)),
+        verifyNotFoundException(fromListenableFuture(
+            rootRangeService.getStream(createGetStreamRequest(colName, streamName))),
             Status.NOT_FOUND);
     }
 
@@ -377,19 +431,16 @@ public class TestRangeStoreImpl {
         String colName = "test-create-namespace-mock-root-storage-container-store";
         String streamName = colName;
 
-        StorageContainer scStore = mock(StorageContainer.class);
-        when(scStore.stop()).thenReturn(FutureUtils.value(null));
-        rangeStore.getRegistry().setStorageContainer(ROOT_STORAGE_CONTAINER_ID, scStore);
         CreateStreamResponse createResp = CreateStreamResponse.newBuilder()
             .setCode(StatusCode.STREAM_EXISTS)
             .build();
         CreateStreamRequest createReq = createCreateStreamRequest(colName, streamName, DEFAULT_STREAM_CONF);
-        when(scStore.createStream(createReq)).thenReturn(
+        when(mockRangeStoreService.createStream(createReq)).thenReturn(
             CompletableFuture.completedFuture(createResp));
 
         CompletableFuture<CreateStreamResponse> createRespFuture =
-            rangeStore.createStream(createReq);
-        verify(scStore, times(1)).createStream(createReq);
+            fromListenableFuture(rootRangeService.createStream(createReq));
+        verify(mockRangeStoreService, times(1)).createStream(createReq);
         assertTrue(createResp == createRespFuture.get());
     }
 
@@ -398,19 +449,16 @@ public class TestRangeStoreImpl {
         String colName = "test-delete-namespace-no-root-storage-container-store";
         String streamName = colName;
 
-        StorageContainer scStore = mock(StorageContainer.class);
-        when(scStore.stop()).thenReturn(FutureUtils.value(null));
-        rangeStore.getRegistry().setStorageContainer(ROOT_STORAGE_CONTAINER_ID, scStore);
         DeleteStreamResponse deleteResp = DeleteStreamResponse.newBuilder()
             .setCode(StatusCode.STREAM_NOT_FOUND)
             .build();
         DeleteStreamRequest deleteReq = createDeleteStreamRequest(colName, streamName);
-        when(scStore.deleteStream(deleteReq)).thenReturn(
+        when(mockRangeStoreService.deleteStream(deleteReq)).thenReturn(
             CompletableFuture.completedFuture(deleteResp));
 
         CompletableFuture<DeleteStreamResponse> deleteRespFuture =
-            rangeStore.deleteStream(deleteReq);
-        verify(scStore, times(1)).deleteStream(deleteReq);
+            fromListenableFuture(rootRangeService.deleteStream(deleteReq));
+        verify(mockRangeStoreService, times(1)).deleteStream(deleteReq);
         assertTrue(deleteResp == deleteRespFuture.get());
     }
 
@@ -419,26 +467,25 @@ public class TestRangeStoreImpl {
         String colName = "test-get-namespace-no-root-storage-container-store";
         String streamName = colName;
 
-        StorageContainer scStore = mock(StorageContainer.class);
-        when(scStore.stop()).thenReturn(FutureUtils.value(null));
-        rangeStore.getRegistry().setStorageContainer(ROOT_STORAGE_CONTAINER_ID, scStore);
         GetStreamResponse getResp = GetStreamResponse.newBuilder()
             .setCode(StatusCode.STREAM_NOT_FOUND)
             .build();
         GetStreamRequest getReq = createGetStreamRequest(colName, streamName);
-        when(scStore.getStream(getReq)).thenReturn(
+        when(mockRangeStoreService.getStream(getReq)).thenReturn(
             CompletableFuture.completedFuture(getResp));
 
         CompletableFuture<GetStreamResponse> getRespFuture =
-            rangeStore.getStream(getReq);
-        verify(scStore, times(1)).getStream(getReq);
+            fromListenableFuture(rootRangeService.getStream(getReq));
+        verify(mockRangeStoreService, times(1)).getStream(getReq);
         assertTrue(getResp == getRespFuture.get());
     }
 
     @Test
     public void testGetActiveRangesNoManager() throws Exception {
-        verifyNotFoundException(
-            rangeStore.getActiveRanges(createGetActiveRangesRequest(12L, 34L)),
+        rangeStore.getRegistry().stopStorageContainer(ROOT_STORAGE_CONTAINER_ID).join();
+
+        verifyNotFoundException(fromListenableFuture(
+            metaRangeService.getActiveRanges(createGetActiveRangesRequest(12L, 34L))),
             Status.NOT_FOUND);
     }
 
@@ -446,25 +493,17 @@ public class TestRangeStoreImpl {
     public void testGetActiveRangesMockManager() throws Exception {
         long scId = System.currentTimeMillis();
 
-        StreamProperties props = StreamProperties.newBuilder(streamProps)
-            .setStorageContainerId(scId)
-            .build();
-
-        StorageContainer scStore = mock(StorageContainer.class);
-        when(scStore.stop()).thenReturn(FutureUtils.value(null));
-        rangeStore.getRegistry().setStorageContainer(scId, scStore);
-
         StorageContainerResponse resp = StorageContainerResponse.newBuilder()
             .setCode(StatusCode.STREAM_NOT_FOUND)
             .build();
         StorageContainerRequest request = createGetActiveRangesRequest(scId, 34L);
 
-        when(scStore.getActiveRanges(request))
+        when(mockRangeStoreService.getActiveRanges(request))
             .thenReturn(CompletableFuture.completedFuture(resp));
 
-        CompletableFuture<StorageContainerResponse> future =
-            rangeStore.getActiveRanges(request);
-        verify(scStore, times(1)).getActiveRanges(request);
+        CompletableFuture<StorageContainerResponse> future = fromListenableFuture(
+            metaRangeService.getActiveRanges(request));
+        verify(mockRangeStoreService, times(1)).getActiveRanges(request);
         assertTrue(resp == future.get());
     }
 
@@ -477,8 +516,8 @@ public class TestRangeStoreImpl {
     public void testPutNoStorageContainer() throws Exception {
         rangeStore.getRegistry().stopStorageContainer(ROOT_STORAGE_CONTAINER_ID).join();
 
-        verifyNotFoundException(
-            rangeStore.put(createPutRequest(ROOT_STORAGE_CONTAINER_ID)),
+        verifyNotFoundException(fromListenableFuture(
+            tableService.put(createPutRequest(ROOT_STORAGE_CONTAINER_ID))),
             Status.NOT_FOUND);
     }
 
@@ -486,8 +525,8 @@ public class TestRangeStoreImpl {
     public void testDeleteNoStorageContainer() throws Exception {
         rangeStore.getRegistry().stopStorageContainer(ROOT_STORAGE_CONTAINER_ID).join();
 
-        verifyNotFoundException(
-            rangeStore.delete(createDeleteRequest(ROOT_STORAGE_CONTAINER_ID)),
+        verifyNotFoundException(fromListenableFuture(
+            tableService.delete(createDeleteRequest(ROOT_STORAGE_CONTAINER_ID))),
             Status.NOT_FOUND);
     }
 
@@ -495,59 +534,50 @@ public class TestRangeStoreImpl {
     public void testRangeNoStorageContainer() throws Exception {
         rangeStore.getRegistry().stopStorageContainer(ROOT_STORAGE_CONTAINER_ID).join();
 
-        verifyNotFoundException(
-            rangeStore.range(createRangeRequest(ROOT_STORAGE_CONTAINER_ID)),
+        verifyNotFoundException(fromListenableFuture(
+            tableService.range(createRangeRequest(ROOT_STORAGE_CONTAINER_ID))),
             Status.NOT_FOUND);
     }
 
     @Test
     public void testRangeMockStorageContainer() throws Exception {
-        StorageContainer scStore = mock(StorageContainer.class);
-        when(scStore.stop()).thenReturn(FutureUtils.value(null));
-        rangeStore.getRegistry().setStorageContainer(ROOT_STORAGE_CONTAINER_ID, scStore);
         StorageContainerResponse response = createRangeResponse(StatusCode.SUCCESS);
         StorageContainerRequest request = createRangeRequest(ROOT_STORAGE_CONTAINER_ID);
 
-        when(scStore.range(request))
+        when(mockRangeStoreService.range(request))
             .thenReturn(CompletableFuture.completedFuture(response));
 
-        CompletableFuture<StorageContainerResponse> future =
-            rangeStore.range(request);
-        verify(scStore, times(1)).range(eq(request));
+        CompletableFuture<StorageContainerResponse> future = fromListenableFuture(
+            tableService.range(request));
+        verify(mockRangeStoreService, times(1)).range(eq(request));
         assertTrue(response == future.get());
     }
 
     @Test
     public void testDeleteMockStorageContainer() throws Exception {
-        StorageContainer scStore = mock(StorageContainer.class);
-        when(scStore.stop()).thenReturn(FutureUtils.value(null));
-        rangeStore.getRegistry().setStorageContainer(ROOT_STORAGE_CONTAINER_ID, scStore);
         StorageContainerResponse response = createDeleteResponse(StatusCode.SUCCESS);
         StorageContainerRequest request = createDeleteRequest(ROOT_STORAGE_CONTAINER_ID);
 
-        when(scStore.delete(request))
+        when(mockRangeStoreService.delete(request))
             .thenReturn(CompletableFuture.completedFuture(response));
 
-        CompletableFuture<StorageContainerResponse> future =
-            rangeStore.delete(request);
-        verify(scStore, times(1)).delete(eq(request));
+        CompletableFuture<StorageContainerResponse> future = fromListenableFuture(
+            tableService.delete(request));
+        verify(mockRangeStoreService, times(1)).delete(eq(request));
         assertTrue(response == future.get());
     }
 
     @Test
     public void testPutMockStorageContainer() throws Exception {
-        StorageContainer scStore = mock(StorageContainer.class);
-        when(scStore.stop()).thenReturn(FutureUtils.value(null));
-        rangeStore.getRegistry().setStorageContainer(ROOT_STORAGE_CONTAINER_ID, scStore);
         StorageContainerResponse response = createPutResponse(StatusCode.SUCCESS);
         StorageContainerRequest request = createPutRequest(ROOT_STORAGE_CONTAINER_ID);
 
-        when(scStore.put(request))
+        when(mockRangeStoreService.put(request))
             .thenReturn(CompletableFuture.completedFuture(response));
 
-        CompletableFuture<StorageContainerResponse> future =
-            rangeStore.put(request);
-        verify(scStore, times(1)).put(eq(request));
+        CompletableFuture<StorageContainerResponse> future = fromListenableFuture(
+            tableService.put(request));
+        verify(mockRangeStoreService, times(1)).put(eq(request));
         assertTrue(response == future.get());
     }
 
diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcMetaRangeService.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcMetaRangeService.java
index 787453f..178ac19 100644
--- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcMetaRangeService.java
+++ b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcMetaRangeService.java
@@ -32,7 +32,7 @@ import org.apache.bookkeeper.stream.proto.storage.GetActiveRangesResponse;
 import org.apache.bookkeeper.stream.proto.storage.StatusCode;
 import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
 import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
-import org.apache.bookkeeper.stream.storage.impl.RangeStoreImpl;
+import org.apache.bookkeeper.stream.storage.api.metadata.RangeStoreService;
 import org.junit.Test;
 
 /**
@@ -48,7 +48,7 @@ public class TestGrpcMetaRangeService {
 
     @Test
     public void testGetActiveRangesSuccess() throws Exception {
-        RangeStoreImpl rangeService = mock(RangeStoreImpl.class);
+        RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcMetaRangeService grpcService = new GrpcMetaRangeService(rangeService);
 
         StorageContainerRequest request = StorageContainerRequest
@@ -79,7 +79,7 @@ public class TestGrpcMetaRangeService {
 
     @Test
     public void testGetActiveRangesFailure() throws Exception {
-        RangeStoreImpl rangeService = mock(RangeStoreImpl.class);
+        RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcMetaRangeService grpcService = new GrpcMetaRangeService(rangeService);
 
         StorageContainerRequest request = StorageContainerRequest
@@ -109,7 +109,7 @@ public class TestGrpcMetaRangeService {
 
     @Test
     public void testGetActiveRangesException() throws Exception {
-        RangeStoreImpl rangeService = mock(RangeStoreImpl.class);
+        RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcMetaRangeService grpcService = new GrpcMetaRangeService(rangeService);
 
         StorageContainerRequest request = StorageContainerRequest
diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcRootRangeService.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcRootRangeService.java
index 7970793..8a6c7a9 100644
--- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcRootRangeService.java
+++ b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcRootRangeService.java
@@ -70,8 +70,8 @@ import org.apache.bookkeeper.stream.proto.storage.GetNamespaceResponse;
 import org.apache.bookkeeper.stream.proto.storage.GetStreamRequest;
 import org.apache.bookkeeper.stream.proto.storage.GetStreamResponse;
 import org.apache.bookkeeper.stream.proto.storage.StatusCode;
+import org.apache.bookkeeper.stream.storage.api.metadata.RangeStoreService;
 import org.apache.bookkeeper.stream.storage.exceptions.StorageException;
-import org.apache.bookkeeper.stream.storage.impl.RangeStoreImpl;
 import org.junit.Test;
 
 /**
@@ -108,7 +108,7 @@ public class TestGrpcRootRangeService {
 
     @Test
     public void testCreateNamespaceSuccess() throws Exception {
-        RangeStoreImpl rangeService = mock(RangeStoreImpl.class);
+        RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService);
         CreateNamespaceResponse createResp = CreateNamespaceResponse.newBuilder()
             .setCode(StatusCode.SUCCESS)
@@ -152,7 +152,7 @@ public class TestGrpcRootRangeService {
 
     @Test
     public void testCreateNamespaceFailure() throws Exception {
-        RangeStoreImpl rangeService = mock(RangeStoreImpl.class);
+        RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService);
         CreateNamespaceResponse createResp = CreateNamespaceResponse.newBuilder()
             .setCode(StatusCode.INTERNAL_SERVER_ERROR)
@@ -195,7 +195,7 @@ public class TestGrpcRootRangeService {
 
     @Test
     public void testDeleteNamespaceSuccess() throws Exception {
-        RangeStoreImpl rangeService = mock(RangeStoreImpl.class);
+        RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService);
         DeleteNamespaceResponse deleteResp = DeleteNamespaceResponse.newBuilder()
             .setCode(StatusCode.SUCCESS)
@@ -237,7 +237,7 @@ public class TestGrpcRootRangeService {
 
     @Test
     public void testDeleteNamespaceFailure() throws Exception {
-        RangeStoreImpl rangeService = mock(RangeStoreImpl.class);
+        RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService);
         DeleteNamespaceResponse deleteResp = DeleteNamespaceResponse.newBuilder()
             .setCode(StatusCode.INTERNAL_SERVER_ERROR)
@@ -279,7 +279,7 @@ public class TestGrpcRootRangeService {
 
     @Test
     public void testGetNamespaceSuccess() throws Exception {
-        RangeStoreImpl rangeService = mock(RangeStoreImpl.class);
+        RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService);
         GetNamespaceResponse getResp = GetNamespaceResponse.newBuilder()
             .setCode(StatusCode.SUCCESS)
@@ -322,7 +322,7 @@ public class TestGrpcRootRangeService {
 
     @Test
     public void testGetNamespaceFailure() throws Exception {
-        RangeStoreImpl rangeService = mock(RangeStoreImpl.class);
+        RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService);
         GetNamespaceResponse getResp = GetNamespaceResponse.newBuilder()
             .setCode(StatusCode.INTERNAL_SERVER_ERROR)
@@ -368,7 +368,7 @@ public class TestGrpcRootRangeService {
 
     @Test
     public void testCreateStreamSuccess() throws Exception {
-        RangeStoreImpl rangeService = mock(RangeStoreImpl.class);
+        RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService);
         CreateStreamResponse createResp = CreateStreamResponse.newBuilder()
             .setCode(StatusCode.SUCCESS)
@@ -413,7 +413,7 @@ public class TestGrpcRootRangeService {
 
     @Test
     public void testCreateStreamFailure() throws Exception {
-        RangeStoreImpl rangeService = mock(RangeStoreImpl.class);
+        RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService);
         CreateStreamResponse createResp = CreateStreamResponse.newBuilder()
             .setCode(StatusCode.INTERNAL_SERVER_ERROR)
@@ -457,7 +457,7 @@ public class TestGrpcRootRangeService {
 
     @Test
     public void testDeleteStreamSuccess() throws Exception {
-        RangeStoreImpl rangeService = mock(RangeStoreImpl.class);
+        RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService);
         DeleteStreamResponse deleteResp = DeleteStreamResponse.newBuilder()
             .setCode(StatusCode.SUCCESS)
@@ -500,7 +500,7 @@ public class TestGrpcRootRangeService {
 
     @Test
     public void testDeleteStreamFailure() throws Exception {
-        RangeStoreImpl rangeService = mock(RangeStoreImpl.class);
+        RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService);
         DeleteStreamResponse deleteResp = DeleteStreamResponse.newBuilder()
             .setCode(StatusCode.INTERNAL_SERVER_ERROR)
@@ -543,7 +543,7 @@ public class TestGrpcRootRangeService {
 
     @Test
     public void testGetStreamSuccess() throws Exception {
-        RangeStoreImpl rangeService = mock(RangeStoreImpl.class);
+        RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService);
         GetStreamResponse getResp = GetStreamResponse.newBuilder()
             .setCode(StatusCode.SUCCESS)
@@ -588,7 +588,7 @@ public class TestGrpcRootRangeService {
 
     @Test
     public void testGetStreamFailure() throws Exception {
-        RangeStoreImpl rangeService = mock(RangeStoreImpl.class);
+        RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService);
         GetStreamResponse getResp = GetStreamResponse.newBuilder()
             .setCode(StatusCode.INTERNAL_SERVER_ERROR)
diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcTableService.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcTableService.java
index ed97dc1..e943fb4 100644
--- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcTableService.java
+++ b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcTableService.java
@@ -38,7 +38,7 @@ import org.apache.bookkeeper.stream.proto.kv.rpc.RoutingHeader;
 import org.apache.bookkeeper.stream.proto.storage.StatusCode;
 import org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest;
 import org.apache.bookkeeper.stream.proto.storage.StorageContainerResponse;
-import org.apache.bookkeeper.stream.storage.api.RangeStore;
+import org.apache.bookkeeper.stream.storage.api.metadata.RangeStoreService;
 import org.junit.Test;
 
 /**
@@ -63,7 +63,7 @@ public class TestGrpcTableService {
 
     @Test
     public void testPutSuccess() throws Exception {
-        RangeStore rangeService = mock(RangeStore.class);
+        RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcTableService grpcService = new GrpcTableService(rangeService);
 
         StorageContainerRequest request = StorageContainerRequest
@@ -95,7 +95,7 @@ public class TestGrpcTableService {
 
     @Test
     public void testPutFailure() throws Exception {
-        RangeStore rangeService = mock(RangeStore.class);
+        RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcTableService grpcService = new GrpcTableService(rangeService);
 
         StorageContainerRequest request = StorageContainerRequest
@@ -126,7 +126,7 @@ public class TestGrpcTableService {
 
     @Test
     public void testPutException() throws Exception {
-        RangeStore rangeService = mock(RangeStore.class);
+        RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcTableService grpcService = new GrpcTableService(rangeService);
 
         StorageContainerRequest request = StorageContainerRequest
@@ -153,7 +153,7 @@ public class TestGrpcTableService {
 
     @Test
     public void testRangeSuccess() throws Exception {
-        RangeStore rangeService = mock(RangeStore.class);
+        RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcTableService grpcService = new GrpcTableService(rangeService);
 
         StorageContainerRequest request = StorageContainerRequest
@@ -184,7 +184,7 @@ public class TestGrpcTableService {
 
     @Test
     public void testRangeActiveRangesFailure() throws Exception {
-        RangeStore rangeService = mock(RangeStore.class);
+        RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcTableService grpcService = new GrpcTableService(rangeService);
 
         StorageContainerRequest request = StorageContainerRequest
@@ -214,7 +214,7 @@ public class TestGrpcTableService {
 
     @Test
     public void testRangeActiveRangesException() throws Exception {
-        RangeStore rangeService = mock(RangeStore.class);
+        RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcTableService grpcService = new GrpcTableService(rangeService);
 
         StorageContainerRequest request = StorageContainerRequest
@@ -240,7 +240,7 @@ public class TestGrpcTableService {
 
     @Test
     public void testDeleteSuccess() throws Exception {
-        RangeStore rangeService = mock(RangeStore.class);
+        RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcTableService grpcService = new GrpcTableService(rangeService);
 
         StorageContainerRequest request = StorageContainerRequest
@@ -271,7 +271,7 @@ public class TestGrpcTableService {
 
     @Test
     public void testDeleteFailure() throws Exception {
-        RangeStore rangeService = mock(RangeStore.class);
+        RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcTableService grpcService = new GrpcTableService(rangeService);
 
         StorageContainerRequest request = StorageContainerRequest
@@ -301,7 +301,7 @@ public class TestGrpcTableService {
 
     @Test
     public void testDeleteException() throws Exception {
-        RangeStore rangeService = mock(RangeStore.class);
+        RangeStoreService rangeService = mock(RangeStoreService.class);
         GrpcTableService grpcService = new GrpcTableService(rangeService);
 
         StorageContainerRequest request = StorageContainerRequest
diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/TestDefaultStorageContainerFactory.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/TestDefaultStorageContainerFactory.java
index ed87fa6..a56623b 100644
--- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/TestDefaultStorageContainerFactory.java
+++ b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/TestDefaultStorageContainerFactory.java
@@ -16,23 +16,14 @@ package org.apache.bookkeeper.stream.storage.impl.sc;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import com.google.common.util.concurrent.ListenableScheduledFuture;
-import com.google.common.util.concurrent.ListeningScheduledExecutorService;
-import java.net.URI;
-import java.util.concurrent.TimeUnit;
-import org.apache.bookkeeper.common.util.OrderedScheduler;
 import org.apache.bookkeeper.stream.storage.api.sc.StorageContainer;
-import org.apache.bookkeeper.stream.storage.conf.StorageConfiguration;
-import org.apache.bookkeeper.stream.storage.impl.store.MVCCStoreFactory;
-import org.apache.commons.configuration.CompositeConfiguration;
+import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerService;
+import org.apache.bookkeeper.stream.storage.api.sc.StorageContainerServiceFactory;
 import org.junit.Test;
-import org.mockito.Mockito;
 
 /**
  * Unit test for {@link DefaultStorageContainerFactory}.
@@ -40,23 +31,15 @@ import org.mockito.Mockito;
 public class TestDefaultStorageContainerFactory {
 
     @Test
-    public void testCreate() throws Exception {
-        OrderedScheduler scheduler = mock(OrderedScheduler.class);
-        OrderedScheduler snapshotScheduler = mock(OrderedScheduler.class);
-        MVCCStoreFactory storeFactory = mock(MVCCStoreFactory.class);
-        ListeningScheduledExecutorService snapshotExecutor = mock(ListeningScheduledExecutorService.class);
-        when(snapshotScheduler.chooseThread(anyLong())).thenReturn(snapshotExecutor);
-        Mockito.doReturn(mock(ListenableScheduledFuture.class))
-            .when(snapshotExecutor).scheduleWithFixedDelay(
-            any(Runnable.class), anyInt(), anyInt(), any(TimeUnit.class));
+    public void testCreate() {
+        StorageContainerServiceFactory mockServiceFactory =
+            mock(StorageContainerServiceFactory.class);
+        StorageContainerService mockService = mock(StorageContainerService.class);
 
+        when(mockServiceFactory.createStorageContainerService(anyLong()))
+            .thenReturn(mockService);
 
-        DefaultStorageContainerFactory factory = new DefaultStorageContainerFactory(
-            new StorageConfiguration(new CompositeConfiguration()),
-            (streamId, rangeId) -> streamId,
-            scheduler,
-            storeFactory,
-            URI.create("distributedlog://127.0.0.1/stream/storage"));
+        DefaultStorageContainerFactory factory = new DefaultStorageContainerFactory(mockServiceFactory);
         StorageContainer sc = factory.createStorageContainer(1234L);
         assertTrue(sc instanceof StorageContainerImpl);
         assertEquals(1234L, sc.getId());
diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/TestStorageContainerRegistryImpl.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/TestStorageContainerRegistryImpl.java
index 7031629..837dbe2 100644
--- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/TestStorageContainerRegistryImpl.java
+++ b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/TestStorageContainerRegistryImpl.java
@@ -11,21 +11,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
 package org.apache.bookkeeper.stream.storage.impl.sc;
 
 import static org.junit.Assert.assertEquals;
@@ -81,7 +66,7 @@ public class TestStorageContainerRegistryImpl {
     @Test
     public void testOperationsAfterClosed() throws Exception {
         StorageContainerFactory scFactory = createStorageContainerFactory();
-        StorageContainerRegistryImpl registry = new StorageContainerRegistryImpl(scFactory, scheduler);
+        StorageContainerRegistryImpl registry = new StorageContainerRegistryImpl(scFactory);
         registry.close();
 
         long scId = 1234L;
@@ -106,7 +91,7 @@ public class TestStorageContainerRegistryImpl {
     @Test
     public void testStopNotFoundStorageContainer() throws Exception {
         StorageContainerFactory scFactory = createStorageContainerFactory();
-        StorageContainerRegistryImpl registry = new StorageContainerRegistryImpl(scFactory, scheduler);
+        StorageContainerRegistryImpl registry = new StorageContainerRegistryImpl(scFactory);
         FutureUtils.result(registry.stopStorageContainer(1234L));
         assertEquals(0, registry.getNumStorageContainers());
     }
@@ -114,7 +99,7 @@ public class TestStorageContainerRegistryImpl {
     @Test
     public void testStartStorageContainerTwice() throws Exception {
         StorageContainerFactory scFactory = createStorageContainerFactory();
-        StorageContainerRegistryImpl registry = new StorageContainerRegistryImpl(scFactory, scheduler);
+        StorageContainerRegistryImpl registry = new StorageContainerRegistryImpl(scFactory);
         FutureUtils.result(registry.startStorageContainer(1234L));
         assertEquals(1, registry.getNumStorageContainers());
         // second time
@@ -140,7 +125,7 @@ public class TestStorageContainerRegistryImpl {
 
         long scId = 1L;
 
-        StorageContainerRegistryImpl registry = new StorageContainerRegistryImpl(factory, scheduler);
+        StorageContainerRegistryImpl registry = new StorageContainerRegistryImpl(factory);
         FutureUtils.result(registry.startStorageContainer(scId));
         assertEquals(1, registry.getNumStorageContainers());
         assertEquals(sc1, registry.getStorageContainer(scId));
diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/ZkStorageContainerManagerTest.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/ZkStorageContainerManagerTest.java
index 193503b..3a5a4fd 100644
--- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/ZkStorageContainerManagerTest.java
+++ b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/ZkStorageContainerManagerTest.java
@@ -35,7 +35,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import org.apache.bookkeeper.clients.utils.NetUtils;
 import org.apache.bookkeeper.common.concurrent.FutureUtils;
 import org.apache.bookkeeper.common.testing.MoreAsserts;
-import org.apache.bookkeeper.common.util.OrderedScheduler;
 import org.apache.bookkeeper.stats.NullStatsLogger;
 import org.apache.bookkeeper.stream.proto.cluster.ClusterAssignmentData;
 import org.apache.bookkeeper.stream.proto.cluster.ServerAssignmentData;
@@ -76,7 +75,6 @@ public class ZkStorageContainerManagerTest extends ZooKeeperClusterTestCase {
     private StorageContainerRegistry scRegistry;
     private ZkClusterMetadataStore clusterMetadataStore;
     private ZkStorageContainerManager scManager;
-    private OrderedScheduler scheduler;
 
     @Before
     public void setup() {
@@ -89,13 +87,8 @@ public class ZkStorageContainerManagerTest extends ZooKeeperClusterTestCase {
             curatorClient, zkServers, "/" + runtime.getMethodName()));
         clusterMetadataStore.initializeCluster(NUM_STORAGE_CONTAINERS);
 
-        scheduler = OrderedScheduler.newSchedulerBuilder()
-            .name("test-scheduler")
-            .numThreads(1)
-            .build();
-
         mockScFactory = mock(StorageContainerFactory.class);
-        scRegistry = spy(new StorageContainerRegistryImpl(mockScFactory, scheduler));
+        scRegistry = spy(new StorageContainerRegistryImpl(mockScFactory));
 
         scManager = new ZkStorageContainerManager(
             myEndpoint,
@@ -112,10 +105,6 @@ public class ZkStorageContainerManagerTest extends ZooKeeperClusterTestCase {
             scManager.close();
         }
 
-        if (null != scheduler) {
-            scheduler.shutdown();
-        }
-
         if (null != curatorClient) {
             curatorClient.close();
         }
@@ -278,7 +267,7 @@ public class ZkStorageContainerManagerTest extends ZooKeeperClusterTestCase {
                 );
             }
         };
-        scRegistry = spy(new StorageContainerRegistryImpl(mockScFactory, scheduler));
+        scRegistry = spy(new StorageContainerRegistryImpl(mockScFactory));
 
         scManager = new ZkStorageContainerManager(
             myEndpoint,
diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/StorageContainerImplTest.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreServiceImplTest.java
similarity index 98%
rename from stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/StorageContainerImplTest.java
rename to stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreServiceImplTest.java
index e2a582b..a4d8710 100644
--- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/sc/StorageContainerImplTest.java
+++ b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/service/RangeStoreServiceImplTest.java
@@ -15,7 +15,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.bookkeeper.stream.storage.impl.sc;
+package org.apache.bookkeeper.stream.storage.impl.service;
 
 import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_DELETE_REQ;
 import static org.apache.bookkeeper.stream.proto.storage.StorageContainerRequest.RequestCase.KV_PUT_REQ;
@@ -73,9 +73,9 @@ import org.junit.Before;
 import org.junit.Test;
 
 /**
- * Unit test of {@link StorageContainerImpl}.
+ * Unit test of {@link RangeStoreServiceImpl}.
  */
-public class StorageContainerImplTest {
+public class RangeStoreServiceImplTest {
 
     private static final long SCID = 3456L;
     private static final long STREAM_ID = 1234L;
@@ -86,7 +86,7 @@ public class StorageContainerImplTest {
     private RootRangeStoreFactory rrStoreFactory;
     private MetaRangeStoreFactory mrStoreFactory;
     private TableStoreFactory tableStoreFactory;
-    private StorageContainerImpl container;
+    private RangeStoreServiceImpl container;
     private OrderedScheduler scheduler;
     private RootRangeStore rrStore;
     private MVCCAsyncStore<byte[], byte[]> rrMvccStore;
@@ -111,7 +111,7 @@ public class StorageContainerImplTest {
         this.mrMvccStore = mock(MVCCAsyncStore.class);
         this.trMvccStore = mock(MVCCAsyncStore.class);
 
-        this.container = new StorageContainerImpl(
+        this.container = new RangeStoreServiceImpl(
             SCID,
             scheduler,
             mvccStoreFactory,
@@ -179,7 +179,7 @@ public class StorageContainerImplTest {
     public void testStartRootContainer() throws Exception {
         mockStorageContainer(ROOT_STORAGE_CONTAINER_ID);
 
-        StorageContainerImpl container = new StorageContainerImpl(
+        RangeStoreServiceImpl container = new RangeStoreServiceImpl(
             ROOT_STORAGE_CONTAINER_ID,
             scheduler,
             mvccStoreFactory,

-- 
To stop receiving notification emails like this one, please contact
sijie@apache.org.

[bookkeeper] 09/09: ISSUE #1472: [TABLE SERVICE] TestStorageClientBuilder.testBuildClientInvalidNamespaceName failed

Posted by si...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sijie pushed a commit to branch branch-4.7
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git

commit 96d599e5ee1c304e73591225297066af35553df7
Author: Sijie Guo <si...@apache.org>
AuthorDate: Mon Jun 4 00:57:09 2018 -0700

    ISSUE #1472: [TABLE SERVICE] TestStorageClientBuilder.testBuildClientInvalidNamespaceName failed
    
    Descriptions of the changes in this PR:
    
    *Problem*
    
     #1457 changed the validation of namespace/stream name. so "-" is a valid character.
    
    *Solution*
    
    Fix the test.
    
    Master Issue: #1472
    
    Author: Sijie Guo <si...@apache.org>
    
    Reviewers: Jia Zhai <None>
    
    This closes #1473 from sijie/fix_storage_client_builder, closes #1472
---
 .../java/org/apache/bookkeeper/clients/TestStorageClientBuilder.java    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/stream/clients/java/all/src/test/java/org/apache/bookkeeper/clients/TestStorageClientBuilder.java b/stream/clients/java/all/src/test/java/org/apache/bookkeeper/clients/TestStorageClientBuilder.java
index 39bd14a..daef4ed 100644
--- a/stream/clients/java/all/src/test/java/org/apache/bookkeeper/clients/TestStorageClientBuilder.java
+++ b/stream/clients/java/all/src/test/java/org/apache/bookkeeper/clients/TestStorageClientBuilder.java
@@ -50,7 +50,7 @@ public class TestStorageClientBuilder {
             .withSettings(StorageClientSettings.newBuilder()
                 .serviceUri("bk://localhost:4181")
                 .build())
-            .withNamespace("invalid-namespace")
+            .withNamespace("invalid namespace")
             .build();
     }
 

-- 
To stop receiving notification emails like this one, please contact
sijie@apache.org.

[bookkeeper] 07/09: [TABLE SERVICE] cleanup : cleanup protobuf definitions

Posted by si...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sijie pushed a commit to branch branch-4.7
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git

commit d8f7cc01c8af9465082c23080715893f4ebc277c
Author: Sijie Guo <si...@apache.org>
AuthorDate: Wed May 30 23:26:08 2018 -0700

    [TABLE SERVICE] cleanup : cleanup protobuf definitions
    
    Descriptions of the changes in this PR:
    
    *Motivation*
    
    There are some unused fields and some fields that were not renamed correctly from col to namespace.
    
    *Solution*
    
    This is a cleanup PR to remove unused fields and rename "col" to "ns" or "namespace".
    
    Author: Sijie Guo <si...@apache.org>
    
    Reviewers: Enrico Olivelli <eo...@gmail.com>, Jia Zhai <None>
    
    This closes #1457 from sijie/cleanup_fields
---
 .../clients/impl/internal/RootRangeClientImpl.java |  4 +-
 .../TestRootRangeClientCreateNamespaceRpc.java     |  2 +-
 .../TestRootRangeClientGetNamespaceRpc.java        |  2 +-
 .../stream/protocol/util/ProtoUtils.java           | 66 +++++++++++-----------
 stream/proto/src/main/proto/storage.proto          | 14 ++---
 stream/proto/src/main/proto/stream.proto           | 16 ++++--
 .../stream/protocol/util/TestProtoUtils.java       | 24 +++++---
 .../storage/impl/metadata/RootRangeStoreImpl.java  | 27 ++++-----
 .../impl/TestStorageContainerStoreImpl.java        |  2 +-
 .../impl/grpc/TestGrpcRootRangeService.java        | 35 ++++--------
 .../impl/metadata/TestRootRangeStoreImpl.java      | 27 +++++----
 11 files changed, 108 insertions(+), 111 deletions(-)

diff --git a/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/internal/RootRangeClientImpl.java b/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/internal/RootRangeClientImpl.java
index 72bb0e1..a8e2603 100644
--- a/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/internal/RootRangeClientImpl.java
+++ b/stream/clients/java/base/src/main/java/org/apache/bookkeeper/clients/impl/internal/RootRangeClientImpl.java
@@ -123,7 +123,7 @@ class RootRangeClientImpl implements RootRangeClient {
                                                 CompletableFuture<NamespaceProperties> createNamespaceFuture) {
         StatusCode code = response.getCode();
         if (StatusCode.SUCCESS == code) {
-            createNamespaceFuture.complete(response.getColProps());
+            createNamespaceFuture.complete(response.getNsProps());
             return;
         }
         createNamespaceFuture.completeExceptionally(createRootRangeException(namespace, code));
@@ -161,7 +161,7 @@ class RootRangeClientImpl implements RootRangeClient {
                                              CompletableFuture<NamespaceProperties> getFuture) {
         StatusCode code = response.getCode();
         if (StatusCode.SUCCESS == code) {
-            getFuture.complete(response.getColProps());
+            getFuture.complete(response.getNsProps());
             return;
         }
         getFuture.completeExceptionally(createRootRangeException(namespace, code));
diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientCreateNamespaceRpc.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientCreateNamespaceRpc.java
index 4c605d1..111ac66 100644
--- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientCreateNamespaceRpc.java
+++ b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientCreateNamespaceRpc.java
@@ -82,7 +82,7 @@ public class TestRootRangeClientCreateNamespaceRpc extends RootRangeClientImplTe
                                         StreamObserver<CreateNamespaceResponse> responseObserver) {
                 responseObserver.onNext(CreateNamespaceResponse.newBuilder()
                     .setCode(StatusCode.SUCCESS)
-                    .setColProps(colProps)
+                    .setNsProps(colProps)
                     .build());
                 responseObserver.onCompleted();
             }
diff --git a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientGetNamespaceRpc.java b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientGetNamespaceRpc.java
index 9301995..edbfeec 100644
--- a/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientGetNamespaceRpc.java
+++ b/stream/clients/java/base/src/test/java/org/apache/bookkeeper/clients/impl/internal/TestRootRangeClientGetNamespaceRpc.java
@@ -82,7 +82,7 @@ public class TestRootRangeClientGetNamespaceRpc extends RootRangeClientImplTestB
                                      StreamObserver<GetNamespaceResponse> responseObserver) {
                 responseObserver.onNext(GetNamespaceResponse.newBuilder()
                     .setCode(StatusCode.SUCCESS)
-                    .setColProps(colProps)
+                    .setNsProps(colProps)
                     .build());
                 responseObserver.onCompleted();
             }
diff --git a/stream/proto/src/main/java/org/apache/bookkeeper/stream/protocol/util/ProtoUtils.java b/stream/proto/src/main/java/org/apache/bookkeeper/stream/protocol/util/ProtoUtils.java
index 687388f..46de480 100644
--- a/stream/proto/src/main/java/org/apache/bookkeeper/stream/protocol/util/ProtoUtils.java
+++ b/stream/proto/src/main/java/org/apache/bookkeeper/stream/protocol/util/ProtoUtils.java
@@ -19,6 +19,7 @@ package org.apache.bookkeeper.stream.protocol.util;
 
 import static com.google.common.base.Preconditions.checkArgument;
 
+import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
 import java.util.List;
 import org.apache.bookkeeper.common.util.Revisioned;
@@ -42,7 +43,6 @@ import org.apache.bookkeeper.stream.proto.storage.OneStorageContainerEndpointReq
 import org.apache.bookkeeper.stream.proto.storage.OneStorageContainerEndpointResponse;
 import org.apache.bookkeeper.stream.proto.storage.StatusCode;
 import org.apache.bookkeeper.stream.proto.storage.StorageContainerEndpoint;
-import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
 
 /**
@@ -89,37 +89,37 @@ public class ProtoUtils {
     }
 
     /**
-     * Validate namespace characters are [a-zA-Z_0-9].
+     * Validate namespace name.
      *
      * @return true if it is a valid namespace name. otherwise false.
      */
     public static boolean validateNamespaceName(String name) {
-        if (StringUtils.isBlank(name)) {
-            return false;
-        }
-        for (int i = 0; i < name.length(); i++) {
-            if (Character.isLetterOrDigit(name.charAt(i)) || name.charAt(i) == '_') {
-                continue;
-            }
-            return false;
-        }
-        return true;
+        return validateStreamName(name);
     }
 
     /**
-     * Validate namespace characters are [a-zA-Z_0-9].
+     * Validate stream name.
+     *
+     * <p>follow the rules that dlog uses for validating stream name.
      *
      * @return true if it is a valid namespace name. otherwise false.
      */
     public static boolean validateStreamName(String name) {
-        if (StringUtils.isBlank(name)) {
+        if (Strings.isNullOrEmpty(name)) {
             return false;
         }
         for (int i = 0; i < name.length(); i++) {
-            if (Character.isLetterOrDigit(name.charAt(i)) || name.charAt(i) == '_') {
-                continue;
+            char c = name.charAt(i);
+            if (c == 0
+                || c == ' '
+                || c == '<'
+                || c == '>'
+                || c > '\u0000' && c < '\u001f'
+                || c > '\u007f' && c < '\u009f'
+                || c > '\ud800' && c < '\uf8ff'
+                || c > '\ufff0' && c < '\uffff') {
+                return false;
             }
-            return false;
         }
         return true;
     }
@@ -243,15 +243,15 @@ public class ProtoUtils {
     /**
      * Create a {@link CreateNamespaceRequest}.
      *
-     * @param colName namespace name
-     * @param colConf namespace conf
+     * @param nsName namespace name
+     * @param nsConf namespace conf
      * @return a create namespace request.
      */
-    public static CreateNamespaceRequest createCreateNamespaceRequest(String colName,
-                                                                      NamespaceConfiguration colConf) {
+    public static CreateNamespaceRequest createCreateNamespaceRequest(String nsName,
+                                                                      NamespaceConfiguration nsConf) {
         return CreateNamespaceRequest.newBuilder()
-            .setName(colName)
-            .setColConf(colConf)
+            .setName(nsName)
+            .setNsConf(nsConf)
             .build();
     }
 
@@ -286,16 +286,16 @@ public class ProtoUtils {
     /**
      * Create a {@link CreateStreamRequest}.
      *
-     * @param colName    namespace name
+     * @param nsName     namespace name
      * @param streamName stream name
      * @param streamConf stream configuration
      * @return a create stream request.
      */
-    public static CreateStreamRequest createCreateStreamRequest(String colName,
+    public static CreateStreamRequest createCreateStreamRequest(String nsName,
                                                                 String streamName,
                                                                 StreamConfiguration streamConf) {
         return CreateStreamRequest.newBuilder()
-            .setColName(colName)
+            .setNsName(nsName)
             .setName(streamName)
             .setStreamConf(streamConf)
             .build();
@@ -304,14 +304,15 @@ public class ProtoUtils {
     /**
      * Create a {@link GetStreamRequest}.
      *
-     * @param colName    namespace name
+     * @param nsName     namespace name
      * @param streamName stream name
      * @return a create stream request.
      */
-    public static GetStreamRequest createGetStreamRequest(String colName, String streamName) {
+    public static GetStreamRequest createGetStreamRequest(String nsName,
+                                                          String streamName) {
         return GetStreamRequest.newBuilder()
             .setStreamName(StreamName.newBuilder()
-                .setColName(colName)
+                .setNamespaceName(nsName)
                 .setStreamName(streamName))
             .build();
     }
@@ -331,14 +332,15 @@ public class ProtoUtils {
     /**
      * Create a {@link DeleteStreamRequest}.
      *
-     * @param colName    namespace name
+     * @param nsName     namespace name
      * @param streamName stream name
      * @return a create stream request.
      */
-    public static DeleteStreamRequest createDeleteStreamRequest(String colName, String streamName) {
+    public static DeleteStreamRequest createDeleteStreamRequest(String nsName,
+                                                                String streamName) {
         return DeleteStreamRequest.newBuilder()
             .setName(streamName)
-            .setColName(colName)
+            .setNsName(nsName)
             .build();
     }
 
diff --git a/stream/proto/src/main/proto/storage.proto b/stream/proto/src/main/proto/storage.proto
index 7570d29..e33ecbe 100644
--- a/stream/proto/src/main/proto/storage.proto
+++ b/stream/proto/src/main/proto/storage.proto
@@ -112,13 +112,13 @@ service MetaRangeService {
 //
 
 message CreateNamespaceRequest {
-    string name                                 = 1;
-    stream.NamespaceConfiguration col_conf     = 2;
+    string name                             = 1;
+    stream.NamespaceConfiguration ns_conf   = 2;
 }
 
 message CreateNamespaceResponse {
-    StatusCode code                             = 1;
-    stream.NamespaceProperties col_props       = 2;
+    StatusCode code                         = 1;
+    stream.NamespaceProperties ns_props     = 2;
 }
 
 message DeleteNamespaceRequest {
@@ -135,11 +135,11 @@ message GetNamespaceRequest {
 
 message GetNamespaceResponse {
     StatusCode code = 1;
-    stream.NamespaceProperties col_props = 2;
+    stream.NamespaceProperties ns_props = 2;
 }
 
 message CreateStreamRequest {
-    string col_name                        = 1;
+    string ns_name                         = 1;
     string name                            = 2;
     stream.StreamConfiguration stream_conf = 3;
 }
@@ -150,7 +150,7 @@ message CreateStreamResponse {
 }
 
 message DeleteStreamRequest {
-    string col_name                      = 1;
+    string ns_name                       = 1;
     string name                          = 2;
 }
 
diff --git a/stream/proto/src/main/proto/stream.proto b/stream/proto/src/main/proto/stream.proto
index 2477b51..150e30f 100644
--- a/stream/proto/src/main/proto/stream.proto
+++ b/stream/proto/src/main/proto/stream.proto
@@ -55,7 +55,7 @@ message RangeProperties {
 enum RangeKeyType {
     NULL        = 0;
     HASH        = 1;
-    RAW         = 2;
+    RAW         = 2; // reserved, not implemented yet
 }
 
 message RangeMetadata {
@@ -85,6 +85,15 @@ message ParentRangesList {
 // Stream
 //
 
+// since stream and table are similar and exchangable,
+// from the beginning, we shared the metadata management
+// between streams and tables and distinguish them using
+// a flag that recorded in metadata.
+enum StorageType {
+    STREAM      = 0;
+    TABLE       = 1;
+}
+
 enum SplitPolicyType {
     FIXED       = 0;
     BANDWIDTH   = 1;
@@ -139,8 +148,7 @@ message StreamConfiguration {
     SplitPolicy split_policy            = 4;
     SegmentRollingPolicy rolling_policy = 5;
     RetentionPolicy retention_policy    = 6;
-    string backend_service_url          = 7;
-    bool is_readonly                    = 8;
+    StorageType storage_type            = 7;
 }
 
 message StreamProperties {
@@ -151,7 +159,7 @@ message StreamProperties {
 }
 
 message StreamName {
-    string col_name     = 1;
+    string namespace_name     = 1;
     string stream_name  = 2;
 }
 
diff --git a/stream/proto/src/test/java/org/apache/bookkeeper/stream/protocol/util/TestProtoUtils.java b/stream/proto/src/test/java/org/apache/bookkeeper/stream/protocol/util/TestProtoUtils.java
index 88cc995..9d1b728 100644
--- a/stream/proto/src/test/java/org/apache/bookkeeper/stream/protocol/util/TestProtoUtils.java
+++ b/stream/proto/src/test/java/org/apache/bookkeeper/stream/protocol/util/TestProtoUtils.java
@@ -56,8 +56,13 @@ public class TestProtoUtils {
         assertTrue(validateNamespaceName("namespace_name"));
         assertTrue(validateNamespaceName("NamespaceName"));
         assertTrue(validateNamespaceName("9NamespaceName"));
-        assertFalse(validateNamespaceName("namespace-name"));
-        assertFalse(validateNamespaceName("!namespace_name"));
+        assertTrue(validateNamespaceName("namespace-name"));
+        assertTrue(validateNamespaceName("!namespace_name"));
+        assertFalse(validateNamespaceName(" namespace_name"));
+        assertFalse(validateNamespaceName("<namespace_name"));
+        assertFalse(validateNamespaceName(">namespace_name"));
+        assertFalse(validateNamespaceName(""));
+        assertFalse(validateNamespaceName(null));
     }
 
     @Test
@@ -65,8 +70,13 @@ public class TestProtoUtils {
         assertTrue(validateStreamName("stream_name"));
         assertTrue(validateStreamName("StreamName"));
         assertTrue(validateStreamName("9StreamName"));
-        assertFalse(validateStreamName("stream-name"));
-        assertFalse(validateStreamName("!stream_name"));
+        assertTrue(validateStreamName("stream-name"));
+        assertTrue(validateStreamName("!stream_name"));
+        assertFalse(validateNamespaceName(" stream_name"));
+        assertFalse(validateNamespaceName("<stream_name"));
+        assertFalse(validateNamespaceName(">stream_name"));
+        assertFalse(validateNamespaceName(""));
+        assertFalse(validateNamespaceName(null));
     }
 
     @Test
@@ -184,14 +194,14 @@ public class TestProtoUtils {
 
     @Test
     public void testCreateCreateNamespaceRequest() {
-        NamespaceConfiguration colConf = NamespaceConfiguration.newBuilder()
+        NamespaceConfiguration nsConf = NamespaceConfiguration.newBuilder()
             .setDefaultStreamConf(DEFAULT_STREAM_CONF)
             .build();
         CreateNamespaceRequest request = createCreateNamespaceRequest(
             name.getMethodName(),
-            colConf);
+            nsConf);
         assertEquals(name.getMethodName(), request.getName());
-        assertEquals(colConf, request.getColConf());
+        assertEquals(nsConf, request.getNsConf());
     }
 
     @Test
diff --git a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/metadata/RootRangeStoreImpl.java b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/metadata/RootRangeStoreImpl.java
index 00863b6..4314bce 100644
--- a/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/metadata/RootRangeStoreImpl.java
+++ b/stream/storage/impl/src/main/java/org/apache/bookkeeper/stream/storage/impl/metadata/RootRangeStoreImpl.java
@@ -22,7 +22,6 @@ import static com.google.common.base.Charsets.UTF_8;
 import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.MIN_DATA_STREAM_ID;
 import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.validateNamespaceName;
 import static org.apache.bookkeeper.stream.protocol.util.ProtoUtils.validateStreamName;
-import static org.apache.commons.lang3.StringUtils.isBlank;
 
 import com.google.protobuf.InvalidProtocolBufferException;
 import java.net.URI;
@@ -220,7 +219,7 @@ public class RootRangeStoreImpl
             .setProps(NamespaceProperties.newBuilder()
                 .setNamespaceId(namespaceId)
                 .setNamespaceName(nsName)
-                .setDefaultStreamConf(request.getColConf().getDefaultStreamConf()))
+                .setDefaultStreamConf(request.getNsConf().getDefaultStreamConf()))
             .build();
 
         byte[] nsNameKey = getNamespaceNameKey(nsName);
@@ -246,7 +245,7 @@ public class RootRangeStoreImpl
                     CreateNamespaceResponse.Builder respBuilder = CreateNamespaceResponse.newBuilder();
                     if (txnResult.isSuccess()) {
                         respBuilder.setCode(StatusCode.SUCCESS);
-                        respBuilder.setColProps(metadata.getProps());
+                        respBuilder.setNsProps(metadata.getProps());
                     } else {
                         // TODO: differentiate the error code
                         respBuilder.setCode(StatusCode.INTERNAL_SERVER_ERROR);
@@ -341,7 +340,7 @@ public class RootRangeStoreImpl
                     nsRespBuilder.setCode(StatusCode.NAMESPACE_NOT_FOUND);
                 } else {
                     nsRespBuilder.setCode(StatusCode.SUCCESS);
-                    nsRespBuilder.setColProps(nsMetadata.getProps());
+                    nsRespBuilder.setNsProps(nsMetadata.getProps());
                 }
                 return nsRespBuilder.build();
             });
@@ -379,7 +378,7 @@ public class RootRangeStoreImpl
     @Override
     public CompletableFuture<CreateStreamResponse> createStream(CreateStreamRequest request) {
         String streamName = request.getName();
-        String nsName = request.getColName();
+        String nsName = request.getNsName();
 
         StatusCode code = verifyStreamRequest(nsName, streamName);
         if (StatusCode.SUCCESS != code) {
@@ -457,19 +456,11 @@ public class RootRangeStoreImpl
         long scId = placementPolicy.placeStreamRange(streamId, 0L);
 
 
-        StreamConfiguration newStreamConf = streamConf;
-        // no backend service url is provided, use the default service url
-        if (isBlank(streamConf.getBackendServiceUrl())) {
-            newStreamConf = StreamConfiguration.newBuilder(streamConf)
-                .setBackendServiceUrl(defaultServiceUri.toString())
-                .build();
-        }
-
         StreamProperties streamProps = StreamProperties.newBuilder()
             .setStreamId(streamId)
             .setStreamName(streamName)
             .setStorageContainerId(scId)
-            .setStreamConf(newStreamConf)
+            .setStreamConf(streamConf)
             .build();
 
         byte[] nsIdKey = getNamespaceIdKey(nsId);
@@ -519,7 +510,7 @@ public class RootRangeStoreImpl
     @Override
     public CompletableFuture<DeleteStreamResponse> deleteStream(DeleteStreamRequest request) {
         String streamName = request.getName();
-        String nsName = request.getColName();
+        String nsName = request.getNsName();
 
         StatusCode code = verifyStreamRequest(nsName, streamName);
         if (StatusCode.SUCCESS != code) {
@@ -599,12 +590,14 @@ public class RootRangeStoreImpl
     public CompletableFuture<GetStreamResponse> getStream(GetStreamRequest request) {
         StreamName streamName = request.getStreamName();
 
-        StatusCode code = verifyStreamRequest(streamName.getColName(), streamName.getStreamName());
+        StatusCode code = verifyStreamRequest(
+            streamName.getNamespaceName(),
+            streamName.getStreamName());
         if (StatusCode.SUCCESS != code) {
             return FutureUtils.value(GetStreamResponse.newBuilder().setCode(code).build());
         }
 
-        byte[] nsNameKey = getNamespaceNameKey(streamName.getColName());
+        byte[] nsNameKey = getNamespaceNameKey(streamName.getNamespaceName());
         GetStreamResponse.Builder respBuilder = GetStreamResponse.newBuilder();
         return store.get(nsNameKey)
             .thenCompose(nsIdBytes -> {
diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/TestStorageContainerStoreImpl.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/TestStorageContainerStoreImpl.java
index 9293117..b9d5e69 100644
--- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/TestStorageContainerStoreImpl.java
+++ b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/TestStorageContainerStoreImpl.java
@@ -112,7 +112,7 @@ public class TestStorageContainerStoreImpl {
 
     private static StreamName createStreamName(String name) {
         return StreamName.newBuilder()
-            .setColName(name + "_col")
+            .setNamespaceName(name + "_col")
             .setStreamName(name + "_stream")
             .build();
     }
diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcRootRangeService.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcRootRangeService.java
index 8a6c7a9..f22e52a 100644
--- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcRootRangeService.java
+++ b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/grpc/TestGrpcRootRangeService.java
@@ -15,21 +15,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
 package org.apache.bookkeeper.stream.storage.impl.grpc;
 
 import static org.apache.bookkeeper.stream.protocol.ProtocolConstants.DEFAULT_STREAM_CONF;
@@ -112,7 +97,7 @@ public class TestGrpcRootRangeService {
         GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService);
         CreateNamespaceResponse createResp = CreateNamespaceResponse.newBuilder()
             .setCode(StatusCode.SUCCESS)
-            .setColProps(namespaceProps)
+            .setNsProps(namespaceProps)
             .build();
         CreateNamespaceRequest createReq = createCreateNamespaceRequest(nsName, namespaceConf);
         when(rangeService.createNamespace(createReq)).thenReturn(
@@ -140,7 +125,7 @@ public class TestGrpcRootRangeService {
         grpcService.createNamespace(
             CreateNamespaceRequest.newBuilder()
                 .setName(nsName)
-                .setColConf(namespaceConf)
+                .setNsConf(namespaceConf)
                 .build(),
             streamObserver);
         latch.await();
@@ -183,7 +168,7 @@ public class TestGrpcRootRangeService {
         grpcService.createNamespace(
             CreateNamespaceRequest.newBuilder()
                 .setName(nsName)
-                .setColConf(namespaceConf)
+                .setNsConf(namespaceConf)
                 .build(),
             streamObserver);
         latch.await();
@@ -283,7 +268,7 @@ public class TestGrpcRootRangeService {
         GrpcRootRangeService grpcService = new GrpcRootRangeService(rangeService);
         GetNamespaceResponse getResp = GetNamespaceResponse.newBuilder()
             .setCode(StatusCode.SUCCESS)
-            .setColProps(namespaceProps)
+            .setNsProps(namespaceProps)
             .build();
         GetNamespaceRequest getReq = createGetNamespaceRequest(nsName);
         when(rangeService.getNamespace(getReq)).thenReturn(
@@ -399,7 +384,7 @@ public class TestGrpcRootRangeService {
         };
         grpcService.createStream(
             CreateStreamRequest.newBuilder()
-                .setColName(nsName)
+                .setNsName(nsName)
                 .setName(streamName)
                 .setStreamConf(DEFAULT_STREAM_CONF)
                 .build(),
@@ -443,7 +428,7 @@ public class TestGrpcRootRangeService {
         };
         grpcService.createStream(
             CreateStreamRequest.newBuilder()
-                .setColName(nsName)
+                .setNsName(nsName)
                 .setName(streamName)
                 .setStreamConf(DEFAULT_STREAM_CONF)
                 .build(),
@@ -487,7 +472,7 @@ public class TestGrpcRootRangeService {
         };
         grpcService.deleteStream(
             DeleteStreamRequest.newBuilder()
-                .setColName(nsName)
+                .setNsName(nsName)
                 .setName(streamName)
                 .build(),
             streamObserver);
@@ -530,7 +515,7 @@ public class TestGrpcRootRangeService {
         };
         grpcService.deleteStream(
             DeleteStreamRequest.newBuilder()
-                .setColName(nsName)
+                .setNsName(nsName)
                 .setName(streamName)
                 .build(),
             streamObserver);
@@ -575,7 +560,7 @@ public class TestGrpcRootRangeService {
         grpcService.getStream(
             GetStreamRequest.newBuilder()
                 .setStreamName(StreamName.newBuilder()
-                    .setColName(nsName)
+                    .setNamespaceName(nsName)
                     .setStreamName(streamName))
                 .build(),
             streamObserver);
@@ -619,7 +604,7 @@ public class TestGrpcRootRangeService {
         grpcService.getStream(
             GetStreamRequest.newBuilder()
                 .setStreamName(StreamName.newBuilder()
-                    .setColName(nsName)
+                    .setNamespaceName(nsName)
                     .setStreamName(streamName))
                 .build(),
             streamObserver);
diff --git a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/metadata/TestRootRangeStoreImpl.java b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/metadata/TestRootRangeStoreImpl.java
index 8179d62..93a9e47 100644
--- a/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/metadata/TestRootRangeStoreImpl.java
+++ b/stream/storage/impl/src/test/java/org/apache/bookkeeper/stream/storage/impl/metadata/TestRootRangeStoreImpl.java
@@ -66,7 +66,6 @@ public class TestRootRangeStoreImpl extends MVCCAsyncStoreTestBase {
 
     private final StreamConfiguration streamConf =
         StreamConfiguration.newBuilder(DEFAULT_STREAM_CONF)
-            .setBackendServiceUrl(DEFAULT_SERVICE_URI)
             .build();
 
 
@@ -136,9 +135,9 @@ public class TestRootRangeStoreImpl extends MVCCAsyncStoreTestBase {
             createCreateNamespaceRequest(nsName, namespaceConf));
         CreateNamespaceResponse response = FutureUtils.result(createFuture);
         assertEquals(StatusCode.SUCCESS, response.getCode());
-        assertEquals(expectedNsId, response.getColProps().getNamespaceId());
-        assertEquals(nsName, response.getColProps().getNamespaceName());
-        assertEquals(namespaceConf.getDefaultStreamConf(), response.getColProps().getDefaultStreamConf());
+        assertEquals(expectedNsId, response.getNsProps().getNamespaceId());
+        assertEquals(nsName, response.getNsProps().getNamespaceName());
+        assertEquals(namespaceConf.getDefaultStreamConf(), response.getNsProps().getDefaultStreamConf());
 
         return response;
     }
@@ -149,8 +148,8 @@ public class TestRootRangeStoreImpl extends MVCCAsyncStoreTestBase {
         CompletableFuture<GetNamespaceResponse> getFuture = rootRangeStore.getNamespace(
             createGetNamespaceRequest(nsName));
         GetNamespaceResponse getResp = FutureUtils.result(getFuture);
-        assertEquals(expectedNsId, getResp.getColProps().getNamespaceId());
-        assertEquals(streamConf, getResp.getColProps().getDefaultStreamConf());
+        assertEquals(expectedNsId, getResp.getNsProps().getNamespaceId());
+        assertEquals(streamConf, getResp.getNsProps().getDefaultStreamConf());
     }
 
     @Test
@@ -170,7 +169,7 @@ public class TestRootRangeStoreImpl extends MVCCAsyncStoreTestBase {
 
         CreateNamespaceResponse response = createNamespaceAndVerify(nsName, 0L);
 
-        verifyNamespaceExists(nsName, response.getColProps().getNamespaceId());
+        verifyNamespaceExists(nsName, response.getNsProps().getNamespaceId());
         verifyNamespaceId(0L);
     }
 
@@ -180,7 +179,7 @@ public class TestRootRangeStoreImpl extends MVCCAsyncStoreTestBase {
 
         // create first namespace
         CreateNamespaceResponse response = createNamespaceAndVerify(nsName, 0L);
-        verifyNamespaceExists(nsName, response.getColProps().getNamespaceId());
+        verifyNamespaceExists(nsName, response.getNsProps().getNamespaceId());
         verifyNamespaceId(0L);
 
         // create the namespace with same name will fail
@@ -215,11 +214,11 @@ public class TestRootRangeStoreImpl extends MVCCAsyncStoreTestBase {
         String nsName = name.getMethodName();
 
         CreateNamespaceResponse createResp = createNamespaceAndVerify(nsName, 0L);
-        verifyNamespaceExists(nsName, createResp.getColProps().getNamespaceId());
+        verifyNamespaceExists(nsName, createResp.getNsProps().getNamespaceId());
         verifyNamespaceId(0L);
 
         deleteNamespaceAndVerify(nsName);
-        verifyNamespaceNotExists(nsName, createResp.getColProps().getNamespaceId());
+        verifyNamespaceNotExists(nsName, createResp.getNsProps().getNamespaceId());
         verifyNamespaceId(0L);
     }
 
@@ -333,7 +332,7 @@ public class TestRootRangeStoreImpl extends MVCCAsyncStoreTestBase {
         createStreamAndVerify(nsName, streamName, MIN_DATA_STREAM_ID);
 
         verifyStreamExists(
-            createResp.getColProps().getNamespaceId(),
+            createResp.getNsProps().getNamespaceId(),
             streamName,
             MIN_DATA_STREAM_ID);
         verifyStreamId(MIN_DATA_STREAM_ID);
@@ -348,7 +347,7 @@ public class TestRootRangeStoreImpl extends MVCCAsyncStoreTestBase {
         createStreamAndVerify(nsName, streamName, MIN_DATA_STREAM_ID);
 
         verifyStreamExists(
-            createResp.getColProps().getNamespaceId(),
+            createResp.getNsProps().getNamespaceId(),
             streamName,
             MIN_DATA_STREAM_ID);
         verifyStreamId(MIN_DATA_STREAM_ID);
@@ -392,7 +391,7 @@ public class TestRootRangeStoreImpl extends MVCCAsyncStoreTestBase {
         createStreamAndVerify(nsName, streamName, MIN_DATA_STREAM_ID);
 
         verifyStreamExists(
-            createResp.getColProps().getNamespaceId(),
+            createResp.getNsProps().getNamespaceId(),
             streamName,
             MIN_DATA_STREAM_ID);
         verifyStreamId(MIN_DATA_STREAM_ID);
@@ -403,7 +402,7 @@ public class TestRootRangeStoreImpl extends MVCCAsyncStoreTestBase {
         assertEquals(StatusCode.SUCCESS, deleteResp.getCode());
 
         verifyStreamNotExists(
-            createResp.getColProps().getNamespaceId(),
+            createResp.getNsProps().getNamespaceId(),
             streamName,
             MIN_DATA_STREAM_ID);
         verifyStreamId(MIN_DATA_STREAM_ID);

-- 
To stop receiving notification emails like this one, please contact
sijie@apache.org.

[bookkeeper] 04/09: Include stream modules in bookkeeper distributions only when `-Dstream` is specified

Posted by si...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sijie pushed a commit to branch branch-4.7
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git

commit 308cf1e196136f6fb714d47f540e50c7aaa38bce
Author: Sijie Guo <si...@apache.org>
AuthorDate: Sun May 27 22:57:22 2018 -0700

    Include stream modules in bookkeeper distributions only when `-Dstream` is specified
    
    Descriptions of the changes in this PR:
    
    *Motivation*
    
    stream modules are only built when `-Dstream` is specified. so if we want to include
    binary distribution, `-Dstream` is needed. This updates those modules with profiles
    that enabled when `-Dstream` is specified.
    
    Author: Sijie Guo <si...@apache.org>
    
    Reviewers: Enrico Olivelli <eo...@gmail.com>
    
    This closes #1447 from sijie/fix_stream_module
---
 bookkeeper-dist/all/pom.xml    | 25 ++++++++++++++++++-------
 bookkeeper-dist/server/pom.xml | 25 ++++++++++++++++++-------
 tests/integration/pom.xml      | 15 ++++++++++++++-
 3 files changed, 50 insertions(+), 15 deletions(-)

diff --git a/bookkeeper-dist/all/pom.xml b/bookkeeper-dist/all/pom.xml
index d1f5b25..ae36e20 100644
--- a/bookkeeper-dist/all/pom.xml
+++ b/bookkeeper-dist/all/pom.xml
@@ -92,13 +92,6 @@
       <version>${project.version}</version>
     </dependency>
 
-    <!-- stream.storage -->
-    <dependency>
-      <groupId>org.apache.bookkeeper</groupId>
-      <artifactId>stream-storage-server</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-
     <!-- bookkeeper benchmark -->
     <dependency>
       <groupId>org.apache.bookkeeper</groupId>
@@ -152,4 +145,22 @@
       </plugin>
     </plugins>
   </build>
+  <profiles>
+    <profile>
+      <id>stream</id>
+      <activation>
+        <property>
+          <name>stream</name>
+        </property>
+      </activation>
+      <dependencies>
+        <!-- stream.storage -->
+        <dependency>
+          <groupId>org.apache.bookkeeper</groupId>
+          <artifactId>stream-storage-server</artifactId>
+          <version>${project.version}</version>
+        </dependency>
+      </dependencies>
+    </profile>
+  </profiles>
 </project>
diff --git a/bookkeeper-dist/server/pom.xml b/bookkeeper-dist/server/pom.xml
index abcd0ef..9021352 100644
--- a/bookkeeper-dist/server/pom.xml
+++ b/bookkeeper-dist/server/pom.xml
@@ -76,13 +76,6 @@
       <version>${project.version}</version>
     </dependency>
 
-    <!-- stream.storage -->
-    <dependency>
-      <groupId>org.apache.bookkeeper</groupId>
-      <artifactId>stream-storage-server</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-
     <!-- slf4j binding -->
     <dependency>
       <groupId>org.slf4j</groupId>
@@ -130,4 +123,22 @@
 
     </plugins>
   </build>
+  <profiles>
+    <profile>
+      <id>stream</id>
+      <activation>
+        <property>
+          <name>stream</name>
+        </property>
+      </activation>
+      <dependencies>
+        <!-- stream.storage -->
+        <dependency>
+          <groupId>org.apache.bookkeeper</groupId>
+          <artifactId>stream-storage-server</artifactId>
+          <version>${project.version}</version>
+        </dependency>
+      </dependencies>
+    </profile>
+  </profiles>
 </project>
diff --git a/tests/integration/pom.xml b/tests/integration/pom.xml
index bcf3622..20d301c 100644
--- a/tests/integration/pom.xml
+++ b/tests/integration/pom.xml
@@ -30,7 +30,6 @@
   <modules>
     <module>smoke</module>
     <module>standalone</module>
-    <module>cluster</module>
   </modules>
 
   <build>
@@ -70,5 +69,19 @@
         </plugins>
       </build>
     </profile>
+
+    <!-- enable building table service related tests only when -Dstream is provided -->
+    <profile>
+      <id>stream</id>
+      <activation>
+        <property>
+          <name>stream</name>
+        </property>
+      </activation>
+      <modules>
+        <!-- enable cluster testing -->
+        <module>cluster</module>
+      </modules>
+    </profile>
   </profiles>
 </project>

-- 
To stop receiving notification emails like this one, please contact
sijie@apache.org.