├── .editorconfig ├── .github └── workflows │ ├── deploy-snapshot.yml │ └── run-tests.yml ├── .gitignore ├── .mvn └── wrapper │ └── maven-wrapper.properties ├── CONTRIBUTING.adoc ├── HOWTO-RELEASE.md ├── LICENSE.txt ├── README.md ├── examples ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── couchbase │ │ └── client │ │ └── dcp │ │ └── examples │ │ ├── AirportsInFrance.java │ │ ├── CheckSessionState.java │ │ ├── CountDocumentSizes.java │ │ ├── FlowControl.java │ │ ├── HighLevelApi.java │ │ ├── PrintIncomingChanges.java │ │ └── WorkloadGenerator.java │ └── resources │ └── log4j2.xml ├── mvnw ├── mvnw.cmd ├── perf ├── README.md ├── build.sh ├── config │ ├── compression-disabled.properties │ ├── compression-enabled.properties │ ├── compression-forced.properties │ ├── high-level-api.properties │ ├── mitigate-rollbacks.properties │ └── turbo.properties └── run.sh ├── pom.xml └── src ├── integrationTest └── java │ └── com │ └── couchbase │ ├── client │ └── dcp │ │ └── test │ │ ├── BasicRebalanceIntegrationTest.java │ │ ├── BasicStreamingIntegrationTest.java │ │ ├── CollectionsBasicStreamingIntegrationTest.java │ │ ├── CollectionsMutationsIntegrationTest.java │ │ ├── DcpIntegrationTestBase.java │ │ ├── FailoverIntegrationTest.java │ │ ├── RemoteAgent.java │ │ ├── RemoteDcpStreamer.java │ │ ├── ScopesIntegrationTest.java │ │ ├── agent │ │ ├── BucketService.java │ │ ├── BucketServiceImpl.java │ │ ├── ClusterService.java │ │ ├── ClusterServiceImpl.java │ │ ├── ClusterSupplier.java │ │ ├── CollectionService.java │ │ ├── CollectionServiceImpl.java │ │ ├── DcpStreamer.java │ │ ├── DocumentService.java │ │ ├── DocumentServiceImpl.java │ │ ├── StreamerService.java │ │ └── StreamerServiceImpl.java │ │ └── util │ │ ├── IntegrationTestHelper.java │ │ ├── MarkableCrc32.java │ │ └── Poller.java │ └── testcontainers │ └── custom │ ├── CouchbaseContainer.java │ ├── CouchbaseService.java │ ├── ExecUtils.java │ ├── Poller.java │ └── VersionUtils.java ├── main ├── java │ └── com │ │ └── couchbase │ │ └── client │ │ └── dcp │ │ ├── Authenticator.java │ │ ├── CertificateAuthenticator.java │ │ ├── Client.java │ │ ├── ClientVersion.java │ │ ├── ConnectionIdGenerator.java │ │ ├── ConnectionNameGenerator.java │ │ ├── ControlEventHandler.java │ │ ├── Credentials.java │ │ ├── CredentialsProvider.java │ │ ├── DataEventHandler.java │ │ ├── DefaultConnectionNameGenerator.java │ │ ├── PasswordAuthenticator.java │ │ ├── SecurityConfig.java │ │ ├── StaticCredentialsProvider.java │ │ ├── StreamFrom.java │ │ ├── StreamTo.java │ │ ├── SystemEventHandler.java │ │ ├── buffer │ │ ├── DcpBucketConfig.java │ │ ├── DcpOps.java │ │ ├── DcpOpsImpl.java │ │ ├── DcpRequestDispatcher.java │ │ ├── FailoverLogResponse.java │ │ ├── NodeToPartitionMultimap.java │ │ ├── ObserveSeqnoResponse.java │ │ ├── PartitionInstance.java │ │ ├── PersistedSeqnos.java │ │ ├── PersistencePollingHandler.java │ │ └── StreamEventBuffer.java │ │ ├── conductor │ │ ├── BucketConfigArbiter.java │ │ ├── BucketConfigSink.java │ │ ├── BucketConfigSource.java │ │ ├── Conductor.java │ │ ├── DcpChannel.java │ │ ├── DcpChannelControlHandler.java │ │ └── NotMyVbucketException.java │ │ ├── config │ │ ├── CompressionMode.java │ │ ├── Control.java │ │ └── DcpControl.java │ │ ├── core │ │ ├── CouchbaseException.java │ │ ├── config │ │ │ ├── AbstractBucketConfig.java │ │ │ ├── BucketCapability.java │ │ │ ├── BucketConfig.java │ │ │ ├── ClusterCapability.java │ │ │ ├── ClusterConfig.java │ │ │ ├── ClusterConfigParser.java │ │ │ ├── ConfigRevision.java │ │ │ ├── CouchbaseBucketConfig.java │ │ │ ├── CouchbaseBucketConfigParser.java │ │ │ ├── KetamaRing.java │ │ │ ├── MemcachedBucketConfig.java │ │ │ ├── MemcachedBucketConfigParser.java │ │ │ ├── MemcachedHashingStrategy.java │ │ │ ├── NetworkSelector.java │ │ │ ├── NodeIdentifier.java │ │ │ ├── NodeInfo.java │ │ │ ├── NodeInfoParser.java │ │ │ ├── PartitionInfo.java │ │ │ ├── PartitionMap.java │ │ │ ├── PortSelector.java │ │ │ └── StandardMemcachedHashingStrategy.java │ │ ├── endpoint │ │ │ ├── SSLException.java │ │ │ └── kv │ │ │ │ └── AuthenticationException.java │ │ ├── env │ │ │ └── resources │ │ │ │ ├── NoOpShutdownHook.java │ │ │ │ └── ShutdownHook.java │ │ ├── event │ │ │ ├── CouchbaseEvent.java │ │ │ ├── EventBus.java │ │ │ └── EventType.java │ │ ├── lang │ │ │ ├── Tuple.java │ │ │ └── Tuple2.java │ │ ├── logging │ │ │ ├── RedactableArgument.java │ │ │ └── RedactionLevel.java │ │ ├── package-info.java │ │ ├── state │ │ │ ├── AbstractStateMachine.java │ │ │ ├── LifecycleState.java │ │ │ ├── NotConnectedException.java │ │ │ └── Stateful.java │ │ ├── time │ │ │ ├── Delay.java │ │ │ ├── ExponentialDelay.java │ │ │ ├── FixedDelay.java │ │ │ └── LinearDelay.java │ │ └── utils │ │ │ ├── CbCollections.java │ │ │ ├── CbStrings.java │ │ │ ├── DefaultObjectMapper.java │ │ │ ├── Events.java │ │ │ ├── JacksonHelper.java │ │ │ ├── MinimalEventBus.java │ │ │ └── UnsignedLEB128.java │ │ ├── error │ │ ├── BootstrapException.java │ │ └── RollbackException.java │ │ ├── events │ │ ├── DcpFailureEvent.java │ │ ├── DefaultDcpEventBus.java │ │ ├── FailedToAddNodeEvent.java │ │ ├── FailedToMovePartitionEvent.java │ │ ├── FailedToRemoveNodeEvent.java │ │ ├── LoggingTracer.java │ │ ├── StreamEndEvent.java │ │ └── Tracer.java │ │ ├── highlevel │ │ ├── CollectionCreated.java │ │ ├── CollectionDropped.java │ │ ├── CollectionFlushed.java │ │ ├── DatabaseChangeListener.java │ │ ├── Deletion.java │ │ ├── DocumentChange.java │ │ ├── FailoverLog.java │ │ ├── FlowControlMode.java │ │ ├── Mutation.java │ │ ├── Rollback.java │ │ ├── ScopeCreated.java │ │ ├── ScopeDropped.java │ │ ├── SeqnoAdvanced.java │ │ ├── SnapshotDetails.java │ │ ├── SnapshotMarker.java │ │ ├── StreamEnd.java │ │ ├── StreamFailure.java │ │ ├── StreamOffset.java │ │ └── internal │ │ │ ├── AsyncEventDispatcher.java │ │ │ ├── BlockingQueueConsumerOps.java │ │ │ ├── CollectionIdAndKey.java │ │ │ ├── CollectionsManifest.java │ │ │ ├── DatabaseChangeConsumerOps.java │ │ │ ├── DatabaseChangeEvent.java │ │ │ ├── EventDispatcher.java │ │ │ ├── EventHandlerAdapter.java │ │ │ ├── FlowControlReceipt.java │ │ │ ├── FlowControllable.java │ │ │ ├── ImmediateEventDispatcher.java │ │ │ ├── KeyExtractor.java │ │ │ └── SimpleThreadFactory.java │ │ ├── message │ │ ├── BucketSelectRequest.java │ │ ├── ContentAndXattrs.java │ │ ├── DataType.java │ │ ├── DcpAddStreamRequest.java │ │ ├── DcpAddStreamResponse.java │ │ ├── DcpBufferAckRequest.java │ │ ├── DcpCloseStreamRequest.java │ │ ├── DcpCloseStreamResponse.java │ │ ├── DcpControlRequest.java │ │ ├── DcpControlResponse.java │ │ ├── DcpDeletionMessage.java │ │ ├── DcpExpirationMessage.java │ │ ├── DcpFailoverLogRequest.java │ │ ├── DcpFailoverLogResponse.java │ │ ├── DcpFlushRequest.java │ │ ├── DcpGetPartitionSeqnosRequest.java │ │ ├── DcpGetPartitionSeqnosResponse.java │ │ ├── DcpMutationMessage.java │ │ ├── DcpNoopRequest.java │ │ ├── DcpNoopResponse.java │ │ ├── DcpOpenConnectionRequest.java │ │ ├── DcpOpenConnectionResponse.java │ │ ├── DcpOpenStreamRequest.java │ │ ├── DcpOpenStreamResponse.java │ │ ├── DcpSeqnoAdvancedRequest.java │ │ ├── DcpSetVbucketStateMessage.java │ │ ├── DcpSnapshotMarkerRequest.java │ │ ├── DcpSnapshotMarkerResponse.java │ │ ├── DcpStreamEndMessage.java │ │ ├── DcpSystemEvent.java │ │ ├── DcpSystemEventRequest.java │ │ ├── HelloFeature.java │ │ ├── HelloRequest.java │ │ ├── MessageUtil.java │ │ ├── OpenConnectionFlag.java │ │ ├── PartitionAndSeqno.java │ │ ├── ResponseStatus.java │ │ ├── RollbackMessage.java │ │ ├── SaslAuthRequest.java │ │ ├── SaslAuthResponse.java │ │ ├── SaslListMechsRequest.java │ │ ├── SaslListMechsResponse.java │ │ ├── SaslStepRequest.java │ │ ├── SaslStepResponse.java │ │ ├── ServerRequest.java │ │ ├── SnapshotMarkerFlag.java │ │ ├── StreamEndReason.java │ │ ├── StreamFlag.java │ │ ├── VbucketState.java │ │ └── VersionRequest.java │ │ ├── metrics │ │ ├── ActionCounter.java │ │ ├── ActionTimer.java │ │ ├── DcpChannelMetrics.java │ │ ├── DcpClientMetrics.java │ │ ├── DefaultDropwizardConfig.java │ │ ├── EventCounter.java │ │ ├── LogLevel.java │ │ └── MetricsContext.java │ │ ├── state │ │ ├── FailoverLogEntry.java │ │ ├── PartitionState.java │ │ ├── SessionState.java │ │ ├── StateFormat.java │ │ └── json │ │ │ ├── SessionStateDeserializer.java │ │ │ └── SessionStateSerializer.java │ │ ├── transport │ │ └── netty │ │ │ ├── AuthHandler.java │ │ │ ├── BucketConfigHandler.java │ │ │ ├── ChannelFlowController.java │ │ │ ├── ChannelFlowControllerImpl.java │ │ │ ├── ChannelUtils.java │ │ │ ├── ClientNoopHandler.java │ │ │ ├── ConnectInterceptingHandler.java │ │ │ ├── DcpConnectHandler.java │ │ │ ├── DcpControlHandler.java │ │ │ ├── DcpLoggingHandler.java │ │ │ ├── DcpMessageHandler.java │ │ │ ├── DcpPipeline.java │ │ │ ├── DcpResponse.java │ │ │ ├── DcpResponseListener.java │ │ │ ├── FlowControlDiagnosticHandler.java │ │ │ ├── HandshakeDeadlineEvent.java │ │ │ ├── HandshakeTimeoutHandler.java │ │ │ └── SslHandlerFactory.java │ │ └── util │ │ ├── AdaptiveDelay.java │ │ ├── AtomicBooleanArray.java │ │ ├── MathUtils.java │ │ ├── PartitionSet.java │ │ ├── UserAgentBuilder.java │ │ └── Version.java └── resources │ └── com │ └── couchbase │ └── client │ └── dcp │ └── version.properties └── test ├── java └── com │ └── couchbase │ └── client │ └── dcp │ ├── DefaultConnectionNameGeneratorTest.java │ ├── Resources.java │ ├── TestHelper.java │ ├── config │ └── CompressionModeTest.java │ ├── core │ ├── config │ │ └── DefaultCouchbaseBucketConfigTest.java │ ├── lang │ │ └── TupleTest.java │ ├── logging │ │ └── RedactableArgumentTest.java │ ├── state │ │ └── AbstractStateMachineTest.java │ ├── time │ │ ├── DelayTest.java │ │ ├── ExponentialDelayTest.java │ │ ├── FixedDelayTest.java │ │ └── LinearDelayTest.java │ └── utils │ │ └── UnsignedLEB128Test.java │ ├── message │ ├── ContentAndXattrsTest.java │ ├── StreamEndReasonTest.java │ └── control │ │ └── OpenConnectionRequestTest.java │ ├── perfrunner │ ├── GenericUri.java │ ├── PerformanceTestConnectionString.java │ └── PerformanceTestDriver.java │ ├── state │ ├── SessionStateRollbackToPositionTest.java │ └── json │ │ ├── SessionStateDeserializerTest.java │ │ └── SessionStateSerializerTest.java │ └── util │ ├── AdaptiveDelayTest.java │ ├── PartitionSetTest.java │ ├── UserAgentBuilderTest.java │ └── VersionTest.java └── resources ├── com └── couchbase │ └── client │ └── dcp │ ├── core │ └── config │ │ ├── cluster_run_two_nodes_same_host.json │ │ ├── config-memcached-7.6.0.json │ │ ├── config_magma_two_nodes.json │ │ ├── config_with_external.json │ │ ├── config_with_host_placeholder.json │ │ ├── config_with_invalid_capability.json │ │ ├── config_with_ipv6.json │ │ ├── config_with_no_partitions.json │ │ ├── ephemeral_bucket_config.json │ │ └── nodes_ext_without_hostname.json │ └── message │ └── encoded-xattrs.txt └── log4j2.xml /.github/workflows/deploy-snapshot.yml: -------------------------------------------------------------------------------- 1 | name: Maven Deploy Snapshot 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | 6 | on: 7 | push: 8 | branches: 9 | - master 10 | paths-ignore: 11 | - '*.md' 12 | - '*.adoc' 13 | - '.gitignore' 14 | - '.editorconfig' 15 | - 'perf/**' 16 | - 'examples/**' 17 | - '.github/workflows/**' 18 | - '!.github/workflows/deploy-snapshot.yml' 19 | 20 | jobs: 21 | build: 22 | runs-on: ubuntu-latest 23 | permissions: 24 | contents: read 25 | 26 | steps: 27 | - uses: actions/checkout@v4 28 | - name: Set up JDK 21 29 | uses: actions/setup-java@v4 30 | with: 31 | java-version: '21' 32 | distribution: 'temurin' 33 | 34 | server-id: 'central' 35 | server-username: MAVEN_USERNAME 36 | server-password: MAVEN_PASSWORD 37 | 38 | - name: Printing maven version 39 | run: ./mvnw --version 40 | 41 | - name: Build and deploy to Maven Central 42 | run: ./mvnw deploy --batch-mode -Dgpg.signer=bc -Psnapshot 43 | env: 44 | MAVEN_USERNAME: ${{ vars.MAVEN_USERNAME }} 45 | MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} 46 | MAVEN_GPG_KEY: ${{ secrets.SDK_ROBOT_GPG_PRIVATE_KEY }} 47 | MAVEN_GPG_PASSPHRASE: '' 48 | -------------------------------------------------------------------------------- /.github/workflows/run-tests.yml: -------------------------------------------------------------------------------- 1 | name: Run Tests 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | 6 | on: 7 | push: 8 | workflow_dispatch: 9 | 10 | jobs: 11 | test: 12 | name: Run Tests 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | include: 17 | - server: '7.2.3' 18 | java-distribution: 'temurin' 19 | java-version: '8' 20 | 21 | # - server: '7.6.5' 22 | # java-distribution: 'temurin' 23 | # java-version: '21' 24 | # 25 | # - server: 'community-7.6.2' 26 | # java-distribution: 'temurin' 27 | # java-version: '17' 28 | # 29 | # - server: '6.6.6' 30 | # java-distribution: 'temurin' 31 | # java-version: '8' 32 | 33 | runs-on: ubuntu-latest 34 | steps: 35 | - uses: actions/checkout@v4 36 | 37 | - uses: actions/setup-java@v4 38 | with: 39 | distribution: ${{ matrix.java-distribution }} 40 | # Version from the matrix is for running tests. Second version is for building the SDK. 41 | java-version: | 42 | ${{ matrix.java-version }} 43 | 17 44 | 45 | - name: Run tests 46 | timeout-minutes: 40 47 | env: 48 | COUCHBASE: ${{ matrix.server }} 49 | run: | 50 | TEST_JAVA_HOME=$JAVA_HOME_${{ matrix.java-version }}_X64 51 | ./mvnw verify --batch-mode -Dmaven.test.failure.ignore=true -Dmaven.javadoc.skip=true -Djvm=${TEST_JAVA_HOME}/bin/java 52 | 53 | - name: Check ResourceLeakDetector results 54 | run: | 55 | if grep "LEAK:" target/surefire-reports/*.xml > leaks.txt; then 56 | cat leaks.txt 57 | echo "Memory leak detected; see task summary for details" >> $GITHUB_STEP_SUMMARY 58 | false 59 | fi 60 | 61 | - name: Publish test results 62 | run: | 63 | curl https://raw.githubusercontent.com/couchbaselabs/junit-markdown/refs/heads/main/JunitMarkdown.java --output ${{ runner.temp }}/JunitMarkdown.java 64 | java ${{ runner.temp }}/JunitMarkdown.java . >> $GITHUB_STEP_SUMMARY 65 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | **/*.iml 3 | target/ 4 | .classpath 5 | .project 6 | .settings/ 7 | .DS_Store 8 | dependency-reduced-pom.xml 9 | .flattened-pom.xml 10 | .gradle 11 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | wrapperVersion=3.3.2 18 | distributionType=only-script 19 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip 20 | -------------------------------------------------------------------------------- /CONTRIBUTING.adoc: -------------------------------------------------------------------------------- 1 | = Contributing 2 | 3 | == Bug reports and feature requests 4 | 5 | If you come across a bug or find something unintuitive, let us know. 6 | We’ll work to fix it in an upcoming release. 7 | 8 | To file a bug report or feature request, go to the https://github.com/couchbase/java-dcp-client/issues[GitHub Issues tab]. 9 | 10 | When filing a bug report, please include: 11 | 12 | * Couchbase Server version 13 | * DCP client version 14 | * Operating system 15 | * A description of the problem 16 | * Detailed steps to reproduce the problem 17 | 18 | == Contributing code 19 | 20 | Whether you have a fix for a typo in a component, a bugfix, or a new feature, we love to receive code from the community! 21 | 22 | It takes a lot of work to get from a potential new bug fix or feature idea to well-tested shipping code. 23 | Our engineers want to help you get there. 24 | 25 | === One-time setup 26 | 27 | The first step is to sign our Contributor License Agreement. 28 | 29 | NOTE: Contributor License Agreements (CLAs) are common for projects under the Apache license, and typically serve to grant control of the code to a central entity. 30 | Because our code is available under the Apache License, signing the CLA doesn’t prevent you from using your code however you like, but it does give Couchbase the ability to defend the source legally and build and maintain a business around the technology. 31 | 32 | Create an account on our http://review.couchbase.org/[Gerrit code review site]. 33 | Make sure the email address you register with matches the email address on your git commits. 34 | You can associate additional email addresses with your Gerrit account later if needed. 35 | 36 | Fill out the agreement under **Settings > Agreements**. 37 | 38 | === Submitting code 39 | 40 | We encourage you to submit patch sets directly to the Gerrit server. 41 | That makes things easier for us, but if you're new to Gerrit it might be intimidating. 42 | Alternatively, free to submit a pull request on GitHub. 43 | -------------------------------------------------------------------------------- /examples/src/main/java/com/couchbase/client/dcp/examples/WorkloadGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.examples; 17 | 18 | import com.couchbase.client.java.Bucket; 19 | import com.couchbase.client.java.Cluster; 20 | import com.couchbase.client.java.Collection; 21 | 22 | import java.util.UUID; 23 | 24 | import static java.util.Collections.singletonMap; 25 | import static java.util.concurrent.TimeUnit.SECONDS; 26 | 27 | /** 28 | * A simple helper class using the SDK to generate some load on the bucket! 29 | */ 30 | public class WorkloadGenerator { 31 | 32 | public static void main(String... args) throws Exception { 33 | Cluster cluster = Cluster.connect("127.0.0.1", "Administrator", "password"); 34 | Bucket bucket = cluster.bucket("default"); 35 | Collection collection = bucket.defaultCollection(); 36 | 37 | while (true) { 38 | for (int i = 0; i < 1024; i++) { 39 | String docId = "doc:" + i; 40 | collection.upsert(docId, singletonMap("uuid", UUID.randomUUID().toString())); 41 | SECONDS.sleep(1); 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /examples/src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /perf/README.md: -------------------------------------------------------------------------------- 1 | # Glue for the Couchbase Perfrunner framework. 2 | 3 | **All commands must be run from the project root directory.** 4 | 5 | To build the test client: 6 | 7 | perf/build.sh 8 | 9 | To run the test client: 10 | 11 | perf/run.sh \ 12 | [process-tracer] 13 | 14 | * `connection-string` - A Couchbase connection string with username, password, host(s), and bucket. 15 | Example: `couchbase://alice:password@127.0.0.1/my-bucket` 16 | * `dcp-message-count` - Total number of DCP mutation, expiration, and deletion messages 17 | the client should receive before terminating. 18 | * `config-properties-file` - Path to a Java properties file containing the settings 19 | for this run. Pre-defined configurations are available 20 | in the `perf/config` directory. 21 | * `process-tracer` - An arbitrary, opaque string that will be passed to the spawned 22 | client Java process as a command line argument. It may be used 23 | to distinguish the client process from other Java processes. 24 | 25 | Reports are generated in the `target/perf` directory. 26 | 27 | Example: 28 | 29 | perf/build.sh 30 | perf/run.sh couchbase://Administrator:password@127.0.0.1/my-bucket 500000 \ 31 | perf/config/compression-enabled.properties xyzzy 32 | 33 | -------------------------------------------------------------------------------- /perf/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | mvn clean test-compile 4 | -------------------------------------------------------------------------------- /perf/config/compression-disabled.properties: -------------------------------------------------------------------------------- 1 | compression=DISABLED 2 | -------------------------------------------------------------------------------- /perf/config/compression-enabled.properties: -------------------------------------------------------------------------------- 1 | compression=ENABLED 2 | -------------------------------------------------------------------------------- /perf/config/compression-forced.properties: -------------------------------------------------------------------------------- 1 | compression=FORCED 2 | -------------------------------------------------------------------------------- /perf/config/high-level-api.properties: -------------------------------------------------------------------------------- 1 | compression=ENABLED 2 | highLevelApi=true 3 | -------------------------------------------------------------------------------- /perf/config/mitigate-rollbacks.properties: -------------------------------------------------------------------------------- 1 | mitigateRollbacks=true 2 | -------------------------------------------------------------------------------- /perf/config/turbo.properties: -------------------------------------------------------------------------------- 1 | compression=ENABLED 2 | skipDecompression=true 3 | -------------------------------------------------------------------------------- /perf/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # See README.md for example usage. 4 | 5 | args="$@" 6 | 7 | mvn exec:java -Dexec.cleanupDaemonThreads=false \ 8 | -Dexec.classpathScope=test \ 9 | -Dexec.mainClass=com.couchbase.client.dcp.perfrunner.PerformanceTestDriver \ 10 | "-Dexec.args=$args" 11 | -------------------------------------------------------------------------------- /src/integrationTest/java/com/couchbase/client/dcp/test/BasicRebalanceIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.couchbase.client.dcp.test; 2 | 3 | import com.couchbase.client.dcp.test.agent.DcpStreamer; 4 | import com.couchbase.testcontainers.custom.CouchbaseContainer; 5 | import org.junit.jupiter.api.Test; 6 | 7 | public class BasicRebalanceIntegrationTest extends DcpIntegrationTestBase { 8 | 9 | @Test 10 | void rebalanceDoesNotDisruptStreaming() throws Exception { 11 | // Don't try to clean up the bucket, since the cluster will be broken 12 | // after the second node is stopped. 13 | final TestBucket bucket = newBucket().replicas(1).create(); 14 | final int batchSize = bucket.createOneDocumentInEachVbucket("a").size(); 15 | 16 | try (RemoteDcpStreamer streamer = bucket.newStreamer().start()) { 17 | streamer.assertStateCount(batchSize, DcpStreamer.State.MUTATIONS); 18 | assertStatus(streamer.status(), batchSize, 0, 0); 19 | 20 | try (CouchbaseContainer secondNode = couchbase().addNode()) { 21 | couchbase().rebalance(); 22 | bucket.createOneDocumentInEachVbucket("b"); 23 | 24 | streamer.assertStateCount(batchSize * 2, DcpStreamer.State.MUTATIONS); 25 | assertStatus(streamer.status(), batchSize * 2, 0, 0); 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/integrationTest/java/com/couchbase/client/dcp/test/FailoverIntegrationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.test; 18 | 19 | import com.couchbase.client.dcp.test.agent.DcpStreamer; 20 | import com.couchbase.testcontainers.custom.CouchbaseContainer; 21 | import org.junit.jupiter.api.AfterAll; 22 | import org.junit.jupiter.api.BeforeAll; 23 | import org.junit.jupiter.api.Test; 24 | 25 | public class FailoverIntegrationTest extends DcpIntegrationTestBase { 26 | 27 | private static CouchbaseContainer secondNode; 28 | 29 | @BeforeAll 30 | public static void startSecondNode() { 31 | secondNode = couchbase().addNode(); 32 | couchbase().rebalance(); 33 | } 34 | 35 | @AfterAll 36 | public static void stopSecondNode() { 37 | stop(secondNode); 38 | } 39 | 40 | @Test 41 | void failover() throws Exception { 42 | final TestBucket bucket = newBucket().replicas(1).create(); 43 | 44 | final int batchSize = bucket.createOneDocumentInEachVbucket("a").size(); 45 | 46 | try (RemoteDcpStreamer streamer = bucket.newStreamer().start()) { 47 | streamer.assertStateCount(batchSize, DcpStreamer.State.MUTATIONS); 48 | 49 | secondNode.failover(); 50 | couchbase().rebalance(); 51 | 52 | bucket.createOneDocumentInEachVbucket("b"); 53 | streamer.assertStateCount(batchSize * 2, DcpStreamer.State.MUTATIONS); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/integrationTest/java/com/couchbase/client/dcp/test/agent/BucketService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.test.agent; 18 | 19 | import reactor.util.annotation.Nullable; 20 | 21 | import java.util.Set; 22 | 23 | public interface BucketService { 24 | /** 25 | * Returns the names of all buckets. 26 | */ 27 | Set list(); 28 | 29 | /** 30 | * Creates a bucket if it doesn't already exist. 31 | * 32 | * @param bucket Name of the bucket to create. 33 | * @param password Password to associate with the bucket (pre-Spock only). 34 | * @param quotaMb Memory quota in megabytes for the bucket. 35 | * @param replicas Number of replicas, or 0 to disable replication. 36 | * @param enableFlush Whether the bucket should support being flushed (reset to empty). 37 | */ 38 | void create(String bucket, int quotaMb, int replicas, boolean enableFlush); 39 | 40 | /** 41 | * Deletes the named bucket if it exists, otherwise does nothing. 42 | * 43 | * @param bucket Name of the bucket to delete. 44 | */ 45 | void delete(String bucket); 46 | } 47 | -------------------------------------------------------------------------------- /src/integrationTest/java/com/couchbase/client/dcp/test/agent/ClusterService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.test.agent; 18 | 19 | public interface ClusterService { 20 | /** 21 | * Resets the Cluster used by the other services. 22 | *

23 | * Prevents the Java SDK from trying to reconnect to buckets that have been deleted. 24 | */ 25 | void reset(); 26 | } 27 | -------------------------------------------------------------------------------- /src/integrationTest/java/com/couchbase/client/dcp/test/agent/ClusterServiceImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.test.agent; 18 | 19 | public class ClusterServiceImpl implements ClusterService { 20 | private final ClusterSupplier clusterSupplier; 21 | 22 | public ClusterServiceImpl(ClusterSupplier clusterSupplier) { 23 | this.clusterSupplier = clusterSupplier; 24 | } 25 | 26 | @Override 27 | public void reset() { 28 | clusterSupplier.reset(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/Authenticator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp; 18 | 19 | import com.couchbase.client.core.deps.io.netty.channel.ChannelPipeline; 20 | import com.couchbase.client.core.deps.io.netty.handler.ssl.SslContextBuilder; 21 | 22 | public interface Authenticator { 23 | 24 | /** 25 | * Allows the authenticator to add KV handlers during connection bootstrap to perform 26 | * authentication. 27 | * 28 | * @param pipeline the pipeline when the endpoint is constructed. 29 | */ 30 | default void authKeyValueConnection(final ChannelPipeline pipeline) { 31 | } 32 | 33 | /** 34 | * The authenticator gets the chance to attach the client certificate to the ssl context if needed. 35 | * 36 | * @param sslContextBuilder the netty context builder 37 | */ 38 | default void applyTlsProperties(final SslContextBuilder sslContextBuilder) { 39 | } 40 | 41 | /** 42 | * If this authenticator only works with encrypted connections. 43 | */ 44 | default boolean requiresTls() { 45 | return false; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/ClientVersion.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp; 18 | 19 | import java.io.InputStream; 20 | import java.io.InputStreamReader; 21 | import java.io.Reader; 22 | import java.util.Properties; 23 | 24 | import static java.nio.charset.StandardCharsets.UTF_8; 25 | 26 | public class ClientVersion { 27 | 28 | private static final String CLIENT_VERSION = loadClientVersion(); 29 | 30 | private static String loadClientVersion() { 31 | try (InputStream is = ClientVersion.class.getResourceAsStream("version.properties"); 32 | Reader r = new InputStreamReader(is, UTF_8)) { 33 | 34 | Properties props = new Properties(); 35 | props.load(r); 36 | 37 | return (String) props.getOrDefault("projectVersion", "unknown"); 38 | 39 | } catch (Throwable t) { 40 | t.printStackTrace(); 41 | return "unknown"; 42 | } 43 | } 44 | 45 | public static String clientVersion() { 46 | return CLIENT_VERSION; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/ConnectionIdGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp; 18 | 19 | import java.util.concurrent.ThreadLocalRandom; 20 | 21 | public class ConnectionIdGenerator { 22 | private static final String clientId = paddedHex(randomLong()); 23 | 24 | public String next() { 25 | return clientId + "/" + paddedHex(randomLong()); 26 | } 27 | 28 | private static String paddedHex(long number) { 29 | return String.format("%016X", number); 30 | } 31 | 32 | private static long randomLong() { 33 | return ThreadLocalRandom.current().nextLong(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/ConnectionNameGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp; 17 | 18 | /** 19 | * A generic interface which determines the name for a DCP connection. 20 | *

21 | * Adhering to the semantics of DCP, it is very important that the names of the connection, if independent 22 | * also need to be different. Otherwise the server will inevitably close the old connection, leading 23 | * to weird edge cases. Keep this in mind when implementing the interface or just stick with the 24 | * default {@link DefaultConnectionNameGenerator}. 25 | * 26 | * @author Michael Nitschinger 27 | * @since 1.0.0 28 | */ 29 | public interface ConnectionNameGenerator { 30 | 31 | int CONNECTION_NAME_MAX_UTF8_BYTES = 200; 32 | 33 | /** 34 | * Generates the name for a DCP Connection. 35 | *

36 | * The UTF-8 encoding of the name must be no longer than {@value #CONNECTION_NAME_MAX_UTF8_BYTES} bytes. 37 | */ 38 | String name(); 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/ControlEventHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | import com.couchbase.client.dcp.transport.netty.ChannelFlowController; 20 | 21 | /** 22 | * This interface acts as a callback on the {@link Client#controlEventHandler(ControlEventHandler)} API 23 | * that allows one to react to control events. 24 | *

25 | * Right now the only event emitted is a {@link com.couchbase.client.dcp.message.RollbackMessage} which 26 | * should be handled appropriately since it indicates that very likely the current consumer state is 27 | * ahead of the server. This happens during failover scenarios and/or if something weird happened 28 | * to the persisted session state. 29 | *

30 | * Keep in mind that the callback is called on the IO event loops, so you should never block or run 31 | * expensive computations in the callback! Use queues and other synchronization primitives! 32 | * 33 | * @author Michael Nitschinger 34 | * @since 1.0.0 35 | */ 36 | public interface ControlEventHandler { 37 | 38 | /** 39 | * Called every time when a control event happens that should be handled by 40 | * consumers of the {@link Client}. 41 | *

42 | * Even if you are not doing anything with the events, make sure to release the buffer!! 43 | * 44 | * @param flowController the flow controller for the passed event. 45 | * @param event the control event happening. 46 | */ 47 | void onEvent(ChannelFlowController flowController, ByteBuf event); 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/Credentials.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2018 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp; 17 | 18 | import static java.util.Objects.requireNonNull; 19 | 20 | 21 | public class Credentials { 22 | 23 | 24 | private final String username; 25 | private final String password; 26 | 27 | public Credentials(String username, String password) { 28 | this.username = requireNonNull(username, "username can't be null"); 29 | this.password = requireNonNull(password, "password can't be null"); 30 | } 31 | 32 | public String getUsername() { 33 | return username; 34 | } 35 | 36 | public String getPassword() { 37 | return password; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/CredentialsProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2018 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp; 17 | 18 | import com.couchbase.client.core.util.HostAndPort; 19 | 20 | public interface CredentialsProvider { 21 | /** 22 | * Get the username/password pair to use for authentication/authorization 23 | * 24 | * @param address 25 | * @return credentials 26 | */ 27 | Credentials get(HostAndPort address); 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/DataEventHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | import com.couchbase.client.dcp.transport.netty.ChannelFlowController; 20 | 21 | /** 22 | * This interface acts as a callback on the {@link Client#dataEventHandler(DataEventHandler)} API 23 | * that allows one to react to data events. 24 | *

25 | * Right now {@link com.couchbase.client.dcp.message.DcpMutationMessage}, 26 | * {@link com.couchbase.client.dcp.message.DcpExpirationMessage} and 27 | * {@link com.couchbase.client.dcp.message.DcpDeletionMessage} are emitted, but the expirations are 28 | * as of Couchbase Server 4.5.0 not actually emitted. So while good practice to handle them, even if 29 | * you opt out to do so make sure to release the buffers. 30 | *

31 | * Keep in mind that the callback is called on the IO event loops, so you should never block or run 32 | * expensive computations in the callback! Use queues and other synchronization primities! 33 | * 34 | * @author Michael Nitschinger 35 | * @since 1.0.0 36 | */ 37 | public interface DataEventHandler { 38 | 39 | /** 40 | * Called when a data event happens. 41 | *

42 | * Make sure to release the buffers!! 43 | * 44 | * @param flowController the flow controller for the passed event. 45 | * @param event the data event happening right now. 46 | */ 47 | void onEvent(ChannelFlowController flowController, ByteBuf event); 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/PasswordAuthenticator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp; 18 | 19 | import com.couchbase.client.core.deps.io.netty.channel.ChannelPipeline; 20 | import com.couchbase.client.core.util.HostAndPort; 21 | import com.couchbase.client.dcp.conductor.DcpChannel; 22 | import com.couchbase.client.dcp.transport.netty.AuthHandler; 23 | 24 | import static java.util.Objects.requireNonNull; 25 | 26 | public class PasswordAuthenticator implements Authenticator { 27 | private final CredentialsProvider credentialsProvider; 28 | 29 | public PasswordAuthenticator(CredentialsProvider credentialsProvider) { 30 | this.credentialsProvider = requireNonNull(credentialsProvider); 31 | } 32 | 33 | @Override 34 | public void authKeyValueConnection(ChannelPipeline pipeline) { 35 | HostAndPort remoteAddress = DcpChannel.getHostAndPort(pipeline.channel()); 36 | Credentials credentials = credentialsProvider.get(remoteAddress); 37 | pipeline.addLast(new AuthHandler(credentials)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/StaticCredentialsProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2018 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp; 17 | 18 | import com.couchbase.client.core.util.HostAndPort; 19 | 20 | public class StaticCredentialsProvider implements CredentialsProvider { 21 | private final Credentials credentials; 22 | 23 | public StaticCredentialsProvider(String username, String password) { 24 | credentials = new Credentials(username, password); 25 | } 26 | 27 | @Override 28 | public Credentials get(HostAndPort address) { 29 | return credentials; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/StreamFrom.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp; 17 | 18 | /** 19 | * From which point in time to start the DCP stream. 20 | * 21 | * @author Michael Nitschinger 22 | * @since 1.0.0 23 | */ 24 | public enum StreamFrom { 25 | /** 26 | * Start at the very beginning - will stream all docs in the bucket. 27 | */ 28 | BEGINNING, 29 | 30 | /** 31 | * Start "now", where now is a time point of execution in the running program where the state 32 | * is gathered from each partition. Mutations will be streamed after this point. 33 | */ 34 | NOW 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/StreamTo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp; 17 | 18 | /** 19 | * Up to which point the DCP stream should run. 20 | * 21 | * @author Michael Nitschinger 22 | * @since 1.0.0 23 | */ 24 | public enum StreamTo { 25 | /** 26 | * Stop "now", where now is the time when the state is initialized that way. 27 | */ 28 | NOW, 29 | 30 | /** 31 | * Never stop streaming automatically, but manual stream stop is of course possible. 32 | */ 33 | INFINITY 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/SystemEventHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp; 17 | 18 | import com.couchbase.client.dcp.core.event.CouchbaseEvent; 19 | 20 | /** 21 | * This interface acts as a callback on the {@link Client#systemEventHandler(SystemEventHandler)} API 22 | * that allows one to react to system events. 23 | */ 24 | public interface SystemEventHandler { 25 | 26 | /** 27 | * Called every time when a system event happens that should be handled by 28 | * consumers of the {@link Client}. 29 | * 30 | * @param event the system event happening. 31 | */ 32 | void onEvent(CouchbaseEvent event); 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/buffer/DcpOps.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.buffer; 18 | 19 | import com.couchbase.client.dcp.core.CouchbaseException; 20 | import com.couchbase.client.dcp.message.ResponseStatus; 21 | import reactor.core.publisher.Mono; 22 | 23 | import static java.util.Objects.requireNonNull; 24 | 25 | public interface DcpOps { 26 | 27 | /** 28 | * Thrown when response status field is non-zero. 29 | */ 30 | class BadResponseStatusException extends CouchbaseException { 31 | private final ResponseStatus status; 32 | 33 | public BadResponseStatusException(ResponseStatus status) { 34 | super(status.toString()); 35 | this.status = requireNonNull(status); 36 | } 37 | 38 | public BadResponseStatusException(ResponseStatus status, String message) { 39 | super(status + " ; " + message); 40 | this.status = requireNonNull(status); 41 | } 42 | 43 | ResponseStatus status() { 44 | return status; 45 | } 46 | } 47 | 48 | Mono observeSeqno(int partition, long vbuuid); 49 | 50 | Mono getFailoverLog(int partition); 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/buffer/FailoverLogResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.buffer; 18 | 19 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 20 | import com.couchbase.client.dcp.message.MessageUtil; 21 | import com.couchbase.client.dcp.state.FailoverLogEntry; 22 | 23 | import java.util.ArrayList; 24 | import java.util.Collections; 25 | import java.util.List; 26 | 27 | class FailoverLogResponse { 28 | private final List logEntries; 29 | 30 | public FailoverLogResponse(final ByteBuf response) { 31 | final ByteBuf content = MessageUtil.getContent(response); 32 | final int numEntries = content.readableBytes() / 16; 33 | final List entries = new ArrayList<>(numEntries); 34 | 35 | for (int i = 0; i < numEntries; i++) { 36 | final long vbuuid = content.readLong(); 37 | final long seqno = content.readLong(); 38 | entries.add(new FailoverLogEntry(seqno, vbuuid)); 39 | } 40 | 41 | this.logEntries = Collections.unmodifiableList(entries); 42 | } 43 | 44 | public List getFailoverLogEntries() { 45 | return logEntries; 46 | } 47 | 48 | public long getCurrentVbuuid() { 49 | return logEntries.get(0).getUuid(); 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | return logEntries.toString(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/buffer/PartitionInstance.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.buffer; 18 | 19 | /** 20 | * Immutable. 21 | */ 22 | class PartitionInstance { 23 | 24 | // The vbucket number. 25 | private final int partition; 26 | 27 | // The "slot" is an index assigned to an instance of the partition. 28 | // When replication is enabled, there are multiple copies of a partition, 29 | // each hosted on a different node. Each copy (instance) has an index 30 | // in the bucket config. The active instance has slot 0, the zero-th replica has slot 1, and so on. 31 | private final int slot; 32 | 33 | PartitionInstance(final int partition, final int slot) { 34 | this.partition = partition; 35 | this.slot = slot; 36 | } 37 | 38 | int partition() { 39 | return partition; 40 | } 41 | 42 | int slot() { 43 | return slot; 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | return partition + "/" + slot; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/conductor/BucketConfigSink.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.conductor; 18 | 19 | import com.couchbase.client.core.util.HostAndPort; 20 | import com.couchbase.client.dcp.core.config.ConfigRevision; 21 | 22 | public interface BucketConfigSink { 23 | void accept(HostAndPort origin, String rawConfig); 24 | 25 | void accept(HostAndPort origin, String rawConfig, ConfigRevision rev); 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/conductor/BucketConfigSource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.conductor; 18 | 19 | import com.couchbase.client.dcp.buffer.DcpBucketConfig; 20 | import reactor.core.publisher.Flux; 21 | 22 | public interface BucketConfigSource { 23 | Flux configs(); 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/conductor/NotMyVbucketException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.conductor; 17 | 18 | import com.couchbase.client.dcp.core.CouchbaseException; 19 | 20 | /** 21 | * Created by daschl on 01/09/16. 22 | */ 23 | public class NotMyVbucketException extends CouchbaseException { 24 | 25 | public NotMyVbucketException() { 26 | } 27 | 28 | public NotMyVbucketException(String message) { 29 | super(message); 30 | } 31 | 32 | public NotMyVbucketException(String message, Throwable cause) { 33 | super(message, cause); 34 | } 35 | 36 | public NotMyVbucketException(Throwable cause) { 37 | super(cause); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/config/Control.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.config; 18 | 19 | import static java.util.Objects.requireNonNull; 20 | 21 | public class Control { 22 | private final String name; 23 | private final String value; 24 | private final boolean optional; 25 | 26 | public Control(String name, String value, boolean optional) { 27 | this.name = requireNonNull(name); 28 | this.value = requireNonNull(value); 29 | this.optional = optional; 30 | } 31 | 32 | public String name() { 33 | return name; 34 | } 35 | 36 | public String value() { 37 | return value; 38 | } 39 | 40 | public boolean isOptional() { 41 | return optional; 42 | } 43 | 44 | @Override 45 | public String toString() { 46 | return name + "=" + value + (optional ? " (optional)" : ""); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/core/CouchbaseException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.core; 17 | 18 | /** 19 | * Common parent exception to build a proper exception hierarchy inside the driver. 20 | */ 21 | public class CouchbaseException extends RuntimeException { 22 | 23 | public CouchbaseException() { 24 | super(); 25 | } 26 | 27 | public CouchbaseException(String message) { 28 | super(message); 29 | } 30 | 31 | public CouchbaseException(String message, Throwable cause) { 32 | super(message, cause); 33 | } 34 | 35 | public CouchbaseException(Throwable cause) { 36 | super(cause); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/core/config/BucketCapability.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.core.config; 18 | 19 | import com.couchbase.client.core.deps.com.fasterxml.jackson.annotation.JsonValue; 20 | 21 | import static java.util.Objects.requireNonNull; 22 | 23 | public enum BucketCapability { 24 | CBHELLO("cbhello"), 25 | TOUCH("touch"), 26 | COUCHAPI("couchapi"), 27 | CCCP("cccp"), 28 | XDCR_CHECKPOINTING("xdcrCheckpointing"), 29 | NODES_EXT("nodesExt"), 30 | DCP("dcp"), 31 | XATTR("xattr"), 32 | SNAPPY("snappy"), 33 | COLLECTIONS("collections"), 34 | DURABLE_WRITE("durableWrite"), 35 | CREATE_AS_DELETED("tombstonedUserXAttrs"), 36 | SUBDOC_REPLACE_BODY_WITH_XATTR("subdoc.ReplaceBodyWithXattr"), 37 | SUBDOC_REVIVE_DOCUMENT("subdoc.ReviveDocument"), 38 | DCP_IGNORE_PURGED_TOMBSTONES("dcp.IgnorePurgedTombstones"), 39 | ; 40 | 41 | private final String wireName; 42 | 43 | BucketCapability(String wireName) { 44 | this.wireName = requireNonNull(wireName); 45 | } 46 | 47 | @JsonValue 48 | public String wireName() { 49 | return wireName; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/core/config/ClusterCapability.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.core.config; 18 | 19 | 20 | import java.util.Arrays; 21 | import java.util.List; 22 | 23 | import static java.util.Collections.unmodifiableList; 24 | import static java.util.Objects.requireNonNull; 25 | 26 | public enum ClusterCapability { 27 | N1QL_ENHANCED_PREPARED_STATEMENTS("n1ql", "enhancedPreparedStatements"), 28 | ; 29 | 30 | public static final List VALUES = unmodifiableList(Arrays.asList(values())); 31 | 32 | private final String namespace; 33 | private final String wireName; 34 | 35 | ClusterCapability(String namespace, String wireName) { 36 | this.namespace = requireNonNull(namespace); 37 | this.wireName = requireNonNull(wireName); 38 | } 39 | 40 | public String namespace() { 41 | return namespace; 42 | } 43 | 44 | public String wireName() { 45 | return wireName; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/core/config/MemcachedBucketConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.core.config; 18 | 19 | import java.util.Set; 20 | 21 | import static java.util.Objects.requireNonNull; 22 | 23 | public class MemcachedBucketConfig extends AbstractBucketConfig { 24 | private final KetamaRing ketamaRing; 25 | 26 | public MemcachedBucketConfig( 27 | String uuid, 28 | String name, 29 | Set capabilities, 30 | KetamaRing ketamaRing 31 | ) { 32 | super(uuid, name, capabilities); 33 | this.ketamaRing = requireNonNull(ketamaRing); 34 | } 35 | 36 | public NodeInfo nodeForKey(final byte[] id) { 37 | return ketamaRing.get(id); 38 | } 39 | 40 | // Visible for testing 41 | KetamaRing ketamaRing() { 42 | return ketamaRing; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/core/config/MemcachedBucketConfigParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.core.config; 18 | 19 | import com.couchbase.client.core.deps.com.fasterxml.jackson.databind.node.ObjectNode; 20 | import com.couchbase.client.core.service.ServiceType; 21 | 22 | import java.util.List; 23 | import java.util.Set; 24 | 25 | import static com.couchbase.client.core.util.CbCollections.filter; 26 | import static com.couchbase.client.dcp.core.config.AbstractBucketConfig.parseBucketCapabilities; 27 | 28 | public class MemcachedBucketConfigParser { 29 | public static MemcachedBucketConfig parse( 30 | ObjectNode configNode, 31 | List nodes, 32 | MemcachedHashingStrategy hashingStrategy 33 | ) { 34 | Set bucketCapabilities = parseBucketCapabilities(configNode); 35 | 36 | List kvNodes = filter(nodes, (it) -> it.has(ServiceType.KV)); 37 | KetamaRing ketamaRing = KetamaRing.create(kvNodes, hashingStrategy); 38 | 39 | return new MemcachedBucketConfig( 40 | configNode.path("name").asText(), 41 | configNode.path("uuid").asText(), 42 | bucketCapabilities, 43 | ketamaRing 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/core/config/MemcachedHashingStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.core.config; 18 | 19 | import com.couchbase.client.core.annotation.Stability; 20 | 21 | /** 22 | * This interface defines different hashing strategies used for ketama hashing in memcached buckets. 23 | */ 24 | @Stability.Internal 25 | public interface MemcachedHashingStrategy { 26 | /** 27 | * The hash for each node based on the node information and repetition. 28 | * 29 | * @param info the node info 30 | * @param repetition the repetition 31 | * @return the hashed node 32 | */ 33 | String hash(NodeInfo info, int repetition); 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/core/config/NodeIdentifier.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.core.config; 18 | 19 | import java.util.Objects; 20 | 21 | import static java.util.Objects.requireNonNull; 22 | 23 | public class NodeIdentifier { 24 | private final String host; 25 | private final int port; 26 | 27 | public NodeIdentifier(String host, int port) { 28 | this.host = requireNonNull(host); 29 | this.port = port; 30 | } 31 | 32 | @Override 33 | public String toString() { 34 | return host + ":" + port; 35 | } 36 | 37 | @Override 38 | public boolean equals(Object o) { 39 | if (this == o) { 40 | return true; 41 | } 42 | if (o == null || getClass() != o.getClass()) { 43 | return false; 44 | } 45 | NodeIdentifier that = (NodeIdentifier) o; 46 | return port == that.port && host.equals(that.host); 47 | } 48 | 49 | @Override 50 | public int hashCode() { 51 | return Objects.hash(host, port); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/core/endpoint/SSLException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.core.endpoint; 17 | 18 | import com.couchbase.client.dcp.core.CouchbaseException; 19 | 20 | public class SSLException extends CouchbaseException { 21 | 22 | public SSLException() { 23 | super(); 24 | } 25 | 26 | public SSLException(String message) { 27 | super(message); 28 | } 29 | 30 | public SSLException(String message, Throwable cause) { 31 | super(message, cause); 32 | } 33 | 34 | public SSLException(Throwable cause) { 35 | super(cause); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/core/endpoint/kv/AuthenticationException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.core.endpoint.kv; 17 | 18 | import com.couchbase.client.dcp.core.CouchbaseException; 19 | 20 | public class AuthenticationException extends CouchbaseException { 21 | 22 | public AuthenticationException() { 23 | super(); 24 | } 25 | 26 | public AuthenticationException(String message) { 27 | super(message); 28 | } 29 | 30 | public AuthenticationException(String message, Throwable cause) { 31 | super(message, cause); 32 | } 33 | 34 | public AuthenticationException(Throwable cause) { 35 | super(cause); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/core/env/resources/NoOpShutdownHook.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.core.env.resources; 17 | 18 | import reactor.core.publisher.Mono; 19 | 20 | /** 21 | * {@link ShutdownHook} hook that does nothing and returns true. 22 | */ 23 | public class NoOpShutdownHook implements ShutdownHook { 24 | @Override 25 | public Mono shutdown() { 26 | return Mono.just(true); 27 | } 28 | 29 | @Override 30 | public boolean isShutdown() { 31 | return true; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/core/env/resources/ShutdownHook.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.core.env.resources; 17 | 18 | import reactor.core.publisher.Mono; 19 | 20 | /** 21 | * Interface to describe shutdown behavior for a resource that 22 | * can be asynchronously shut down. 23 | */ 24 | public interface ShutdownHook { 25 | Mono shutdown(); 26 | 27 | boolean isShutdown(); 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/core/event/CouchbaseEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.core.event; 17 | 18 | import java.util.Map; 19 | 20 | /** 21 | * Defines the generic couchbase event pushed through the event bus. 22 | */ 23 | public interface CouchbaseEvent { 24 | 25 | /** 26 | * The type of the event. 27 | * 28 | * @return the event type. 29 | */ 30 | EventType type(); 31 | 32 | /** 33 | * Converts the event into a map representation of simple types. 34 | * 35 | * @return the map representation. 36 | */ 37 | Map toMap(); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/core/event/EventBus.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.core.event; 17 | 18 | import reactor.core.publisher.Flux; 19 | 20 | public interface EventBus { 21 | 22 | /** 23 | * Subscribe to the event bus to retrieve {@link CouchbaseEvent}s. 24 | * 25 | * @return the observable where the events are emitted into. 26 | */ 27 | Flux get(); 28 | 29 | /** 30 | * Publish a {@link CouchbaseEvent} into the bus. 31 | * 32 | * @param event the event to publish. 33 | */ 34 | void publish(CouchbaseEvent event); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/core/event/EventType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.core.event; 17 | 18 | public enum EventType { 19 | 20 | /** 21 | * The event contains some kind of metric. 22 | */ 23 | METRIC, 24 | 25 | /** 26 | * The event is system state related. 27 | */ 28 | SYSTEM 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/core/lang/Tuple.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.core.lang; 17 | 18 | /** 19 | * Static factory class for various Tuples. 20 | *

21 | * A tuple should be used if more than one argument needs to be passed through a observable. Note that there are 22 | * intentionally only tuples with a maximum of five elements, because if more are needed it hurts readability and 23 | * value objects should be used instead. Also keep in mind that if a tuple is used instead of a value object semantics 24 | * might get lost, so use them sparingly. 25 | */ 26 | public final class Tuple { 27 | 28 | /** 29 | * Forbidding instantiation. 30 | */ 31 | private Tuple() { 32 | } 33 | 34 | /** 35 | * Creates a tuple with two values. 36 | * 37 | * @param v1 the first value. 38 | * @param v2 the second value. 39 | * @return a tuple containing the values. 40 | */ 41 | public static Tuple2 create(final T1 v1, final T2 v2) { 42 | return new Tuple2(v1, v2); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/core/logging/RedactionLevel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.core.logging; 18 | 19 | import static java.util.Objects.requireNonNull; 20 | 21 | /** 22 | * Allows to specify the level of log redaction. 23 | */ 24 | public enum RedactionLevel { 25 | /** 26 | * No redaction is performed, this is the default 27 | */ 28 | NONE, 29 | /** 30 | * Only user data is redacted, system and metadata are not. 31 | */ 32 | PARTIAL, 33 | /** 34 | * User, System and Metadata are all redacted. 35 | */ 36 | FULL; 37 | 38 | private static volatile RedactionLevel level = NONE; 39 | 40 | public static RedactionLevel get() { 41 | return level; 42 | } 43 | 44 | public static void set(RedactionLevel level) { 45 | RedactionLevel.level = requireNonNull(level); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/core/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * These are the bits of core-io 1.x that the DCP client depends on. 3 | */ 4 | package com.couchbase.client.dcp.core; 5 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/core/state/LifecycleState.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.core.state; 18 | 19 | /** 20 | * **Represents common lifecycle states of components.** 21 | * 22 | *

The {@link LifecycleState}s are usually combined with the {@link AbstractStateMachine} to build up a state-machine 23 | * like, observable component that can be subscribed from external components.

24 | * 25 | *
26 |  *
27 |  *     [*] --> Disconnected
28 |  *     Disconnected --> Connecting
29 |  *     Connecting --> Disconnected
30 |  *     Connecting --> Connected
31 |  *     Connecting --> Degraded
32 |  *     Connected --> Disconnecting
33 |  *     Connected --> Degraded
34 |  *     Degraded --> Connected
35 |  *     Disconnecting -> Disconnected
36 |  *
37 |  * 
38 | */ 39 | public enum LifecycleState { 40 | 41 | /** 42 | * The component is currently disconnected. 43 | */ 44 | DISCONNECTED, 45 | 46 | /** 47 | * The component is currently connecting or reconnecting. 48 | */ 49 | CONNECTING, 50 | 51 | /** 52 | * The component is connected without degradation. 53 | */ 54 | CONNECTED, 55 | 56 | /** 57 | * The component is disconnecting. 58 | */ 59 | DISCONNECTING, 60 | 61 | /** 62 | * The component is connected, but with service degradation. 63 | */ 64 | DEGRADED, 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/core/state/NotConnectedException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.core.state; 17 | 18 | import com.couchbase.client.dcp.core.CouchbaseException; 19 | 20 | /** 21 | * Thrown if the stateful component is not connected. 22 | */ 23 | public class NotConnectedException extends CouchbaseException { 24 | 25 | private static final long serialVersionUID = 1093906979963191815L; 26 | 27 | public NotConnectedException() { 28 | super(); 29 | } 30 | 31 | public NotConnectedException(String message) { 32 | super(message); 33 | } 34 | 35 | public NotConnectedException(String message, Throwable cause) { 36 | super(message, cause); 37 | } 38 | 39 | public NotConnectedException(Throwable cause) { 40 | super(cause); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/core/state/Stateful.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.core.state; 17 | 18 | /** 19 | * A stateful component that changes its state and notifies subscribed parties. 20 | */ 21 | public interface Stateful { 22 | 23 | 24 | /** 25 | * Returns the current state. 26 | * 27 | * @return the current state. 28 | */ 29 | S state(); 30 | 31 | /** 32 | * Check if the given state is the same as the current one. 33 | * 34 | * @param state the stats to check against. 35 | * @return true if it is the same, false otherwise. 36 | */ 37 | boolean isState(S state); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/core/time/FixedDelay.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.core.time; 17 | 18 | import java.util.concurrent.TimeUnit; 19 | 20 | /** 21 | * Delay which is fixed for every attempt. 22 | */ 23 | public class FixedDelay extends Delay { 24 | 25 | private final long delay; 26 | 27 | FixedDelay(long delay, TimeUnit unit) { 28 | super(unit); 29 | this.delay = delay; 30 | } 31 | 32 | @Override 33 | public long calculate(long attempt) { 34 | return delay; 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return "FixedDelay{" + delay + " " + unit() + "}"; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/core/time/LinearDelay.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.core.time; 17 | 18 | import java.util.concurrent.TimeUnit; 19 | 20 | /** 21 | * Delay which increases linearly for every attempt. 22 | */ 23 | public class LinearDelay extends Delay { 24 | 25 | private final double growBy; 26 | private final long lower; 27 | private final long upper; 28 | 29 | LinearDelay(TimeUnit unit, long upper, long lower, double growBy) { 30 | super(unit); 31 | if (lower > upper) { 32 | throw new IllegalArgumentException("The lower value must be smaller or equal to the upper value!"); 33 | } 34 | this.growBy = growBy; 35 | this.lower = lower; 36 | this.upper = upper; 37 | } 38 | 39 | @Override 40 | public long calculate(long attempt) { 41 | long calc = Math.round(attempt * growBy); 42 | if (calc < lower) { 43 | return lower; 44 | } 45 | if (calc > upper) { 46 | return upper; 47 | } 48 | return calc; 49 | } 50 | 51 | @Override 52 | public String toString() { 53 | final StringBuilder sb = new StringBuilder("LinearDelay{"); 54 | sb.append("growBy ").append(growBy); 55 | sb.append(" " + unit()); 56 | sb.append("; lower=").append(lower); 57 | sb.append(", upper=").append(upper); 58 | sb.append('}'); 59 | return sb.toString(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/core/utils/CbStrings.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.core.utils; 18 | 19 | import reactor.util.annotation.Nullable; 20 | 21 | public class CbStrings { 22 | private CbStrings() { 23 | throw new AssertionError("not instantiable"); 24 | } 25 | 26 | public static String defaultIfEmpty(@Nullable String s, String defaultValue) { 27 | return s == null || s.isEmpty() 28 | ? defaultValue 29 | : s; 30 | } 31 | 32 | public static String truncate(String s, int maxLength) { 33 | return s.length() <= maxLength ? s : s.substring(0, maxLength); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/core/utils/Events.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.core.utils; 17 | 18 | import com.couchbase.client.dcp.core.event.CouchbaseEvent; 19 | 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | 23 | /** 24 | * Utility methods for event handling. 25 | */ 26 | public class Events { 27 | 28 | /** 29 | * Takes a {@link CouchbaseEvent} and returns a map with event information. 30 | * 31 | * @param source the source event. 32 | * @return a new map which contains name and type info in an event sub-map. 33 | */ 34 | public static Map identityMap(CouchbaseEvent source) { 35 | Map root = new HashMap(); 36 | Map event = new HashMap(); 37 | 38 | event.put("name", source.getClass().getSimpleName().replaceAll("Event$", "")); 39 | event.put("type", source.type().toString()); 40 | root.put("event", event); 41 | 42 | return root; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/core/utils/MinimalEventBus.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.core.utils; 18 | 19 | import com.couchbase.client.core.annotation.Stability; 20 | import com.couchbase.client.core.cnc.Event; 21 | import com.couchbase.client.core.cnc.EventBus; 22 | import com.couchbase.client.core.cnc.EventSubscription; 23 | import com.couchbase.client.core.cnc.LoggingEventConsumer; 24 | import reactor.core.publisher.Mono; 25 | 26 | import java.time.Duration; 27 | import java.util.function.Consumer; 28 | 29 | /** 30 | * Simple implementation that synchronously logs events. 31 | */ 32 | @Stability.Internal 33 | public class MinimalEventBus implements EventBus { 34 | 35 | public static final EventBus INSTANCE = new MinimalEventBus(); 36 | 37 | private final LoggingEventConsumer loggingEventConsumer = LoggingEventConsumer.create(); 38 | 39 | @Override 40 | public synchronized PublishResult publish(Event event) { 41 | loggingEventConsumer.accept(event); 42 | return PublishResult.SUCCESS; 43 | } 44 | 45 | @Override 46 | public EventSubscription subscribe(Consumer consumer) { 47 | throw new UnsupportedOperationException(); 48 | } 49 | 50 | @Override 51 | public void unsubscribe(EventSubscription subscription) { 52 | throw new UnsupportedOperationException(); 53 | } 54 | 55 | @Override 56 | public Mono start() { 57 | return Mono.empty(); 58 | } 59 | 60 | @Override 61 | public Mono stop(Duration timeout) { 62 | return Mono.empty(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/error/BootstrapException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.error; 17 | 18 | import com.couchbase.client.dcp.core.CouchbaseException; 19 | 20 | /** 21 | * This exception indicates an error during bootstrap. See the cause and message for more details. 22 | */ 23 | public class BootstrapException extends CouchbaseException { 24 | 25 | public BootstrapException() { 26 | } 27 | 28 | public BootstrapException(String message) { 29 | super(message); 30 | } 31 | 32 | public BootstrapException(String message, Throwable cause) { 33 | super(message, cause); 34 | } 35 | 36 | public BootstrapException(Throwable cause) { 37 | super(cause); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/error/RollbackException.java: -------------------------------------------------------------------------------- 1 | package com.couchbase.client.dcp.error; 2 | 3 | import com.couchbase.client.dcp.core.CouchbaseException; 4 | 5 | /** 6 | * Indicates a rollback happened, used as an internal messaging event. 7 | */ 8 | public class RollbackException extends CouchbaseException { 9 | 10 | public RollbackException() { 11 | } 12 | 13 | public RollbackException(String message) { 14 | super(message); 15 | } 16 | 17 | public RollbackException(String message, Throwable cause) { 18 | super(message, cause); 19 | } 20 | 21 | public RollbackException(Throwable cause) { 22 | super(cause); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/events/DcpFailureEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.events; 18 | 19 | import java.util.OptionalInt; 20 | 21 | public interface DcpFailureEvent { 22 | /** 23 | * The partition (vbucket) which has caused issue, or empty if not specific to a vbucket 24 | */ 25 | OptionalInt partition(); 26 | 27 | Throwable error(); 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/events/DefaultDcpEventBus.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.events; 18 | 19 | import com.couchbase.client.dcp.core.event.CouchbaseEvent; 20 | import com.couchbase.client.dcp.core.event.EventBus; 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | import reactor.core.publisher.DirectProcessor; 24 | import reactor.core.publisher.Flux; 25 | import reactor.core.publisher.FluxProcessor; 26 | import reactor.core.publisher.FluxSink; 27 | import reactor.core.scheduler.Scheduler; 28 | 29 | public class DefaultDcpEventBus implements EventBus { 30 | 31 | private static final Logger LOGGER = LoggerFactory.getLogger(DefaultDcpEventBus.class); 32 | 33 | private final FluxProcessor bus = DirectProcessor.create(); 34 | private final FluxSink sink = bus.sink(FluxSink.OverflowStrategy.BUFFER); 35 | 36 | private final Scheduler scheduler; 37 | 38 | public DefaultDcpEventBus(final Scheduler scheduler) { 39 | this.scheduler = scheduler; 40 | } 41 | 42 | @Override 43 | public Flux get() { 44 | return bus.onBackpressureBuffer().publishOn(scheduler); 45 | } 46 | 47 | @Override 48 | public void publish(final CouchbaseEvent event) { 49 | try { 50 | sink.next(event); 51 | } catch (Exception ex) { 52 | LOGGER.warn("Caught exception during event emission, moving on.", ex); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/events/StreamEndEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.events; 18 | 19 | import com.couchbase.client.dcp.core.event.CouchbaseEvent; 20 | import com.couchbase.client.dcp.core.event.EventType; 21 | import com.couchbase.client.dcp.core.utils.Events; 22 | import com.couchbase.client.dcp.message.StreamEndReason; 23 | 24 | import java.util.Map; 25 | 26 | /** 27 | * Event published when stream has stopped activity. 28 | */ 29 | public class StreamEndEvent implements CouchbaseEvent { 30 | private final int partition; 31 | private final StreamEndReason reason; 32 | 33 | public StreamEndEvent(int partition, StreamEndReason reason) { 34 | this.partition = partition; 35 | this.reason = reason; 36 | } 37 | 38 | @Override 39 | public EventType type() { 40 | return EventType.SYSTEM; 41 | } 42 | 43 | public int partition() { 44 | return partition; 45 | } 46 | 47 | public StreamEndReason reason() { 48 | return reason; 49 | } 50 | 51 | @Override 52 | public Map toMap() { 53 | Map result = Events.identityMap(this); 54 | result.put("partition", partition); 55 | result.put("reason", reason); 56 | return result; 57 | } 58 | 59 | @Override 60 | public String toString() { 61 | return "StreamEndEvent{" + 62 | "partition=" + partition + 63 | "reason=" + reason + 64 | '}'; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/events/Tracer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License") {} 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.events; 18 | 19 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 20 | import com.couchbase.client.core.deps.io.netty.channel.Channel; 21 | import com.couchbase.client.core.util.HostAndPort; 22 | 23 | import java.util.Map; 24 | 25 | /** 26 | * Callback handler for various events that might occur while the DCP client 27 | * is running. Methods might be called from non-blocking IO threads, 28 | * and must return quickly without making blocking calls. 29 | */ 30 | public interface Tracer { 31 | 32 | /** 33 | * An instance that ignores all events. 34 | */ 35 | Tracer NOOP = new Tracer() { 36 | }; 37 | 38 | default void onConnectionOpen(String channel) { 39 | } 40 | 41 | default void onConnectionClose(String channel) { 42 | } 43 | 44 | default void onStreamStart(HostAndPort address, int partition, long partitionUuid, long startSeqno, long endSeqno, long snapshotStartSeqno, long snapshotEndSeqno, Map value) { 45 | } 46 | 47 | default void onStreamStartFailed(HostAndPort address, int partition, String cause) { 48 | } 49 | 50 | default void onDataEvent(ByteBuf buf, Channel channel) { 51 | } 52 | 53 | default void onControlEvent(ByteBuf buf, Channel channel) { 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/highlevel/Deletion.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.highlevel; 18 | 19 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 20 | import com.couchbase.client.dcp.highlevel.internal.CollectionsManifest; 21 | import com.couchbase.client.dcp.highlevel.internal.FlowControlReceipt; 22 | 23 | public class Deletion extends DocumentChange { 24 | private final boolean dueToExpiration; 25 | 26 | public Deletion(ByteBuf byteBuf, CollectionsManifest.CollectionInfo collectionInfo, String key, FlowControlReceipt receipt, StreamOffset offset, boolean dueToExpiration) { 27 | super(byteBuf, collectionInfo, key, receipt, offset); 28 | 29 | this.dueToExpiration = dueToExpiration; 30 | } 31 | 32 | public boolean isDueToExpiration() { 33 | return dueToExpiration; 34 | } 35 | 36 | @Override 37 | public void dispatch(DatabaseChangeListener listener) { 38 | listener.onDeletion(this); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/highlevel/FailoverLog.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.highlevel; 18 | 19 | import com.couchbase.client.dcp.highlevel.internal.DatabaseChangeEvent; 20 | import com.couchbase.client.dcp.state.FailoverLogEntry; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | import static java.util.Collections.unmodifiableList; 26 | 27 | public class FailoverLog implements DatabaseChangeEvent { 28 | private final int vbucket; 29 | private final List entries; 30 | 31 | public FailoverLog(int vbucket, List entries) { 32 | this.vbucket = vbucket; 33 | this.entries = unmodifiableList(new ArrayList<>(entries)); 34 | } 35 | 36 | @Override 37 | public int getVbucket() { 38 | return vbucket; 39 | } 40 | 41 | public List getEntries() { 42 | return entries; 43 | } 44 | 45 | @Override 46 | public void dispatch(DatabaseChangeListener listener) { 47 | listener.onFailoverLog(this); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/highlevel/FlowControlMode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.highlevel; 18 | 19 | public enum FlowControlMode { 20 | /** 21 | * In this mode, {@link Mutation} and {@link Deletion} events are automatically acknowledged 22 | * prior to dispatch to the {@link DatabaseChangeListener}. 23 | *

24 | * Suitable for listeners whose {@link DatabaseChangeListener#onMutation(Mutation)} 25 | * and {@link DatabaseChangeListener#onDeletion(Deletion)} methods either completely process 26 | * the event (for example, by writing it to disk) or implictly generate backpressure (for example, 27 | * by writing the event to a bounded blocking queue). 28 | */ 29 | AUTOMATIC, 30 | 31 | /** 32 | * In this mode, the listener is responsible for calling {@link DocumentChange#flowControlAck()} 33 | * after each {@link Mutation} and {@link Deletion} event is processed. 34 | *

35 | * NOTE: This mode is not recommended, since it can be difficult to ensure events are 36 | * acknowledged on all code paths, and failure to ACK can cause the server to stop sending events. 37 | */ 38 | MANUAL 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/highlevel/Mutation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.highlevel; 18 | 19 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 20 | import com.couchbase.client.dcp.highlevel.internal.CollectionsManifest; 21 | import com.couchbase.client.dcp.highlevel.internal.FlowControlReceipt; 22 | import com.couchbase.client.dcp.message.DcpMutationMessage; 23 | 24 | public class Mutation extends DocumentChange { 25 | private final int flags; 26 | private final int expiry; 27 | private final int lockTime; 28 | 29 | public Mutation(ByteBuf byteBuf, CollectionsManifest.CollectionInfo collectionInfo, String key, FlowControlReceipt receipt, StreamOffset offset) { 30 | super(byteBuf, collectionInfo, key, receipt, offset); 31 | 32 | this.flags = DcpMutationMessage.flags(byteBuf); 33 | this.expiry = DcpMutationMessage.expiry(byteBuf); 34 | this.lockTime = DcpMutationMessage.lockTime(byteBuf); 35 | } 36 | 37 | public int getExpiry() { 38 | return expiry; 39 | } 40 | 41 | public int getLockTime() { 42 | return lockTime; 43 | } 44 | 45 | public int getFlagsAsInt() { 46 | return flags; 47 | } 48 | 49 | public boolean isJson() { 50 | final int commonFlags = flags >> 24; 51 | if (commonFlags == 0) { 52 | return flags == 0; 53 | } 54 | 55 | return (commonFlags & 0xf) == 2; 56 | } 57 | 58 | @Override 59 | public void dispatch(DatabaseChangeListener listener) { 60 | listener.onMutation(this); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/highlevel/SeqnoAdvanced.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.highlevel; 18 | 19 | import com.couchbase.client.dcp.highlevel.internal.DatabaseChangeEvent; 20 | 21 | import static java.util.Objects.requireNonNull; 22 | 23 | /** 24 | * Think of this as a document change event without a document. 25 | */ 26 | public class SeqnoAdvanced implements DatabaseChangeEvent { 27 | private final int vbucket; 28 | private final StreamOffset offset; 29 | 30 | public SeqnoAdvanced(int vbucket, StreamOffset offset) { 31 | this.vbucket = vbucket; 32 | this.offset = requireNonNull(offset); 33 | } 34 | 35 | @Override 36 | public void dispatch(DatabaseChangeListener listener) { 37 | listener.onSeqnoAdvanced(this); 38 | } 39 | 40 | public int getVbucket() { 41 | return vbucket; 42 | } 43 | 44 | public StreamOffset getOffset() { 45 | return offset; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/highlevel/SnapshotDetails.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.highlevel; 18 | 19 | import com.couchbase.client.dcp.highlevel.internal.DatabaseChangeEvent; 20 | import com.couchbase.client.dcp.message.SnapshotMarkerFlag; 21 | 22 | import java.util.Arrays; 23 | import java.util.List; 24 | import java.util.Set; 25 | 26 | import static java.util.Collections.unmodifiableList; 27 | 28 | public class SnapshotDetails implements DatabaseChangeEvent { 29 | // Cache the values since Enum.values() returns a new array on every call. 30 | private static final List flagValues = unmodifiableList( 31 | Arrays.asList(SnapshotMarkerFlag.values())); 32 | 33 | private final int vbucket; 34 | private final int flags; 35 | private final SnapshotMarker marker; 36 | 37 | public SnapshotDetails(int vbucket, int flags, SnapshotMarker marker) { 38 | this.vbucket = vbucket; 39 | this.flags = flags; 40 | this.marker = marker; 41 | } 42 | 43 | @Override 44 | public void dispatch(DatabaseChangeListener listener) { 45 | listener.onSnapshot(this); 46 | } 47 | 48 | @Override 49 | public int getVbucket() { 50 | return vbucket; 51 | } 52 | 53 | public Set getFlags() { 54 | // lazy creation, since most users don't care about flags. 55 | return SnapshotMarkerFlag.decode(flags); 56 | } 57 | 58 | public int getFlagsAsInt() { 59 | return flags; 60 | } 61 | 62 | public SnapshotMarker getMarker() { 63 | return marker; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/highlevel/StreamEnd.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.highlevel; 18 | 19 | import com.couchbase.client.dcp.highlevel.internal.DatabaseChangeEvent; 20 | import com.couchbase.client.dcp.message.StreamEndReason; 21 | 22 | import static java.util.Objects.requireNonNull; 23 | 24 | public class StreamEnd implements DatabaseChangeEvent { 25 | private final int vbucket; 26 | private final StreamEndReason reason; 27 | 28 | public StreamEnd(int vbucket, StreamEndReason reason) { 29 | this.vbucket = vbucket; 30 | this.reason = requireNonNull(reason); 31 | } 32 | 33 | @Override 34 | public void dispatch(DatabaseChangeListener listener) { 35 | listener.onStreamEnd(this); 36 | } 37 | 38 | @Override 39 | public int getVbucket() { 40 | return vbucket; 41 | } 42 | 43 | public StreamEndReason getReason() { 44 | return reason; 45 | } 46 | 47 | public String toString() { 48 | return "Stream " + vbucket + " ended: " + reason; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/highlevel/StreamFailure.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.highlevel; 18 | 19 | import com.couchbase.client.dcp.highlevel.internal.DatabaseChangeEvent; 20 | 21 | import static java.util.Objects.requireNonNull; 22 | 23 | public class StreamFailure implements DatabaseChangeEvent { 24 | private final int vbucket; 25 | private final Throwable throwable; 26 | 27 | public StreamFailure(int vbucket, Throwable throwable) { 28 | this.vbucket = vbucket; 29 | this.throwable = requireNonNull(throwable); 30 | } 31 | 32 | @Override 33 | public void dispatch(DatabaseChangeListener listener) { 34 | listener.onFailure(this); 35 | } 36 | 37 | public Throwable getCause() { 38 | return throwable; 39 | } 40 | 41 | /** 42 | * Returns the partition that experience the failure, or -1 if the failure is not specific to a partition. 43 | */ 44 | @Override 45 | public int getVbucket() { 46 | return vbucket; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/highlevel/internal/BlockingQueueConsumerOps.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.highlevel.internal; 18 | 19 | import java.util.concurrent.TimeUnit; 20 | 21 | /** 22 | * Subset of the BlockingQueue interface that should be exposed to consumers. 23 | * 24 | * @param queue element type 25 | */ 26 | public interface BlockingQueueConsumerOps { 27 | 28 | /** 29 | * Retrieves and removes the head of this queue, waiting if necessary 30 | * until an element becomes available. 31 | * 32 | * @return the head of this queue 33 | * @throws InterruptedException if interrupted while waiting 34 | */ 35 | T take() throws InterruptedException; 36 | 37 | /** 38 | * Retrieves and removes the head of this queue, waiting up to the 39 | * specified wait time if necessary for an element to become available. 40 | * 41 | * @param timeout how long to wait before giving up, in units of {@code unit} 42 | * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter 43 | * @return the head of this queue, or {@code null} if the specified waiting time elapses 44 | * before an element is available 45 | * @throws InterruptedException if interrupted while waiting 46 | */ 47 | T poll(long timeout, TimeUnit unit) throws InterruptedException; 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/highlevel/internal/CollectionIdAndKey.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.highlevel.internal; 18 | 19 | import static java.util.Objects.requireNonNull; 20 | 21 | public class CollectionIdAndKey { 22 | private final long collectionId; 23 | private final String key; 24 | 25 | public CollectionIdAndKey(long collectionId, String key) { 26 | this.collectionId = collectionId; 27 | this.key = requireNonNull(key); 28 | } 29 | 30 | public static CollectionIdAndKey forDefaultCollection(String key) { 31 | return new CollectionIdAndKey(0, key); 32 | } 33 | 34 | public long collectionId() { 35 | return collectionId; 36 | } 37 | 38 | public String key() { 39 | return key; 40 | } 41 | 42 | @Override 43 | public String toString() { 44 | return collectionId + "/" + key; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/highlevel/internal/DatabaseChangeConsumerOps.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.highlevel.internal; 18 | 19 | import com.couchbase.client.dcp.highlevel.FlowControlMode; 20 | 21 | import java.util.concurrent.BlockingQueue; 22 | import java.util.concurrent.TimeUnit; 23 | 24 | import static java.util.Objects.requireNonNull; 25 | 26 | /** 27 | * Optionally auto-acknowledges events as they are consumed. 28 | */ 29 | public class DatabaseChangeConsumerOps implements BlockingQueueConsumerOps { 30 | private final BlockingQueue queue; 31 | 32 | private final boolean ackOnConsume; 33 | 34 | public DatabaseChangeConsumerOps(BlockingQueue queue, FlowControlMode flowControlMode) { 35 | this.queue = requireNonNull(queue); 36 | this.ackOnConsume = requireNonNull(flowControlMode) == FlowControlMode.AUTOMATIC; 37 | } 38 | 39 | @Override 40 | public DatabaseChangeEvent take() throws InterruptedException { 41 | return maybeAck(queue.take()); 42 | } 43 | 44 | @Override 45 | public DatabaseChangeEvent poll(long timeout, TimeUnit unit) throws InterruptedException { 46 | return maybeAck(queue.poll(timeout, unit)); 47 | } 48 | 49 | private DatabaseChangeEvent maybeAck(DatabaseChangeEvent change) { 50 | if (ackOnConsume && change instanceof FlowControllable) { 51 | ((FlowControllable) change).flowControlAck(); 52 | } 53 | return change; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/highlevel/internal/DatabaseChangeEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.highlevel.internal; 18 | 19 | import com.couchbase.client.dcp.highlevel.DatabaseChangeListener; 20 | 21 | public interface DatabaseChangeEvent { 22 | /** 23 | * Pass this event to the appropriate method of the given listener. 24 | *

25 | * The listener is invoked immediately in the same thread that calls this method. 26 | */ 27 | void dispatch(DatabaseChangeListener listener); 28 | 29 | /** 30 | * Returns the id of the virtual bucket associated with this event, 31 | * or -1 if the event is not associated with a specific virtual bucket. 32 | */ 33 | int getVbucket(); 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/highlevel/internal/EventDispatcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.highlevel.internal; 18 | 19 | import java.time.Duration; 20 | 21 | public interface EventDispatcher { 22 | void dispatch(DatabaseChangeEvent event); 23 | 24 | void gracefulShutdown(); 25 | 26 | void shutdownNow(); 27 | 28 | boolean awaitTermination(Duration timeout) throws InterruptedException; 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/highlevel/internal/FlowControlReceipt.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.highlevel.internal; 18 | 19 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 20 | import com.couchbase.client.dcp.transport.netty.ChannelFlowController; 21 | 22 | import java.util.concurrent.atomic.AtomicBoolean; 23 | 24 | import static com.couchbase.client.dcp.message.MessageUtil.requiresFlowControlAck; 25 | import static java.util.Objects.requireNonNull; 26 | 27 | public class FlowControlReceipt { 28 | private final ChannelFlowController flowController; 29 | private final int ackByteCount; 30 | private final AtomicBoolean acknowledged = new AtomicBoolean(); 31 | 32 | private static final FlowControlReceipt dummy = new FlowControlReceipt(ChannelFlowController.dummy, 0) { 33 | @Override 34 | public void acknowledge() { 35 | } 36 | }; 37 | 38 | public FlowControlReceipt(ChannelFlowController flowController, int ackByteCount) { 39 | this.flowController = requireNonNull(flowController); 40 | this.ackByteCount = ackByteCount; 41 | } 42 | 43 | public void acknowledge() { 44 | if (acknowledged.compareAndSet(false, true)) { 45 | flowController.ack(ackByteCount); 46 | } 47 | } 48 | 49 | public static FlowControlReceipt forMessage(ChannelFlowController flowController, ByteBuf message) { 50 | return requiresFlowControlAck(message) 51 | ? new FlowControlReceipt(flowController, message.readableBytes()) 52 | : dummy; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/highlevel/internal/FlowControllable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.highlevel.internal; 18 | 19 | public interface FlowControllable { 20 | /** 21 | * Must be idempotent. 22 | */ 23 | void flowControlAck(); 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/highlevel/internal/ImmediateEventDispatcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.highlevel.internal; 18 | 19 | import com.couchbase.client.dcp.highlevel.DatabaseChangeListener; 20 | 21 | import java.time.Duration; 22 | 23 | import static java.util.Objects.requireNonNull; 24 | 25 | /** 26 | * Dispatches events in the same thread that calls the dispatch method. 27 | */ 28 | public class ImmediateEventDispatcher implements EventDispatcher { 29 | private final DatabaseChangeListener listener; 30 | 31 | public ImmediateEventDispatcher(DatabaseChangeListener listener) { 32 | this.listener = requireNonNull(listener); 33 | } 34 | 35 | @Override 36 | public void dispatch(DatabaseChangeEvent event) { 37 | event.dispatch(listener); 38 | } 39 | 40 | @Override 41 | public boolean awaitTermination(Duration timeout) throws InterruptedException { 42 | return true; 43 | } 44 | 45 | @Override 46 | public void gracefulShutdown() { 47 | } 48 | 49 | @Override 50 | public void shutdownNow() { 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/highlevel/internal/KeyExtractor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.highlevel.internal; 18 | 19 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 20 | import com.couchbase.client.dcp.core.utils.UnsignedLEB128; 21 | import com.couchbase.client.dcp.message.MessageUtil; 22 | 23 | import static java.nio.charset.StandardCharsets.UTF_8; 24 | 25 | /** 26 | * Knows how to parse the collection ID out of a message's key field. 27 | */ 28 | public interface KeyExtractor { 29 | // When collections are enabled, the key is prefixed by a LEB-128 encoded collection ID. 30 | KeyExtractor COLLECTIONS = event -> { 31 | ByteBuf keyBuf = MessageUtil.getKey(event); 32 | return new CollectionIdAndKey(UnsignedLEB128.read(keyBuf), keyBuf.toString(UTF_8)); 33 | }; 34 | 35 | // When collections are disabled, every key is implicitly in the default collection which has ID zero. 36 | KeyExtractor NO_COLLECTIONS = event -> CollectionIdAndKey.forDefaultCollection( 37 | MessageUtil.getKeyAsString(event)); 38 | 39 | CollectionIdAndKey getCollectionIdAndKey(ByteBuf event); 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/highlevel/internal/SimpleThreadFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.highlevel.internal; 18 | 19 | import java.util.concurrent.ThreadFactory; 20 | import java.util.concurrent.atomic.AtomicInteger; 21 | import java.util.function.Consumer; 22 | 23 | import static java.util.Objects.requireNonNull; 24 | 25 | public class SimpleThreadFactory implements ThreadFactory { 26 | private final AtomicInteger nextId = new AtomicInteger(); 27 | private final String baseName; 28 | private final Consumer customizer; 29 | 30 | public SimpleThreadFactory(String baseName, Consumer customizer) { 31 | this.baseName = requireNonNull(baseName); 32 | this.customizer = requireNonNull(customizer); 33 | } 34 | 35 | @Override 36 | public Thread newThread(Runnable r) { 37 | requireNonNull(r); 38 | 39 | Thread t = new Thread(r); 40 | t.setName(baseName + nextId.getAndIncrement()); 41 | customizer.accept(t); 42 | return t; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/BucketSelectRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | 20 | public enum BucketSelectRequest { 21 | ; 22 | 23 | public static void init(ByteBuf buffer, String bucket) { 24 | MessageUtil.initRequest(MessageUtil.SELECT_BUCKET_OPCODE, buffer); 25 | MessageUtil.setKey(bucket, buffer); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/DataType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.message; 18 | 19 | import java.util.Arrays; 20 | import java.util.EnumSet; 21 | import java.util.List; 22 | 23 | import static java.util.Collections.unmodifiableList; 24 | 25 | /** 26 | * https://github.com/couchbase/kv_engine/blob/master/docs/BinaryProtocol.md#data-types 27 | */ 28 | public enum DataType { 29 | JSON(0x01), 30 | SNAPPY(0x02), 31 | XATTR(0x04); 32 | 33 | private final int bitmask; 34 | 35 | private static final List values = unmodifiableList(Arrays.asList(values())); 36 | 37 | DataType(int bitmask) { 38 | this.bitmask = bitmask; 39 | } 40 | 41 | public int bitmask() { 42 | return bitmask; 43 | } 44 | 45 | public static EnumSet parse(int bitfield) { 46 | EnumSet result = EnumSet.noneOf(DataType.class); 47 | for (DataType type : values) { 48 | if (contains(bitfield, type)) { 49 | result.add(type); 50 | } 51 | } 52 | return result; 53 | } 54 | 55 | public static boolean contains(int bitfield, DataType type) { 56 | return (bitfield & type.bitmask()) != 0; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/DcpAddStreamRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | import com.couchbase.client.core.deps.io.netty.buffer.Unpooled; 20 | 21 | import java.util.Set; 22 | 23 | import static com.couchbase.client.dcp.message.MessageUtil.DCP_ADD_STREAM_OPCODE; 24 | 25 | /** 26 | * Sent to the consumer to tell the consumer to initiate a stream request with the producer 27 | */ 28 | public enum DcpAddStreamRequest { 29 | ; 30 | 31 | public static boolean is(final ByteBuf buffer) { 32 | return buffer.getByte(0) == MessageUtil.MAGIC_REQ && buffer.getByte(1) == DCP_ADD_STREAM_OPCODE; 33 | } 34 | 35 | public static int flagsAsInt(final ByteBuf buffer) { 36 | return MessageUtil.getExtras(buffer).getInt(0); 37 | } 38 | 39 | public static Set flags(final ByteBuf buffer) { 40 | return StreamFlag.decode(flagsAsInt(buffer)); 41 | } 42 | 43 | public static void init(final ByteBuf buffer) { 44 | MessageUtil.initRequest(DCP_ADD_STREAM_OPCODE, buffer); 45 | flags(buffer, 0); 46 | } 47 | 48 | public static void flags(final ByteBuf buffer, int flags) { 49 | ByteBuf extras = Unpooled.buffer(4); 50 | MessageUtil.setExtras(extras.writeInt(flags), buffer); 51 | extras.release(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/DcpAddStreamResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | import com.couchbase.client.core.deps.io.netty.buffer.Unpooled; 20 | 21 | import static com.couchbase.client.dcp.message.MessageUtil.DCP_ADD_STREAM_OPCODE; 22 | 23 | public enum DcpAddStreamResponse { 24 | ; 25 | 26 | public static boolean is(final ByteBuf buffer) { 27 | return buffer.getByte(0) == MessageUtil.MAGIC_RES && buffer.getByte(1) == DCP_ADD_STREAM_OPCODE; 28 | } 29 | 30 | public static void init(final ByteBuf buffer, int opaque) { 31 | MessageUtil.initResponse(DCP_ADD_STREAM_OPCODE, buffer); 32 | opaque(buffer, opaque); 33 | } 34 | 35 | /** 36 | * The opaque field contains the opaque value used by messages passing for that VBucket. 37 | */ 38 | public static int opaque(final ByteBuf buffer) { 39 | return MessageUtil.getExtras(buffer).getInt(0); 40 | } 41 | 42 | public static void opaque(final ByteBuf buffer, int opaque) { 43 | ByteBuf extras = Unpooled.buffer(4); 44 | MessageUtil.setExtras(extras.writeInt(opaque), buffer); 45 | extras.release(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/DcpBufferAckRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | import com.couchbase.client.core.deps.io.netty.buffer.Unpooled; 20 | 21 | import static com.couchbase.client.dcp.message.MessageUtil.DCP_BUFFER_ACK_OPCODE; 22 | 23 | public enum DcpBufferAckRequest { 24 | ; 25 | 26 | public static boolean is(final ByteBuf buffer) { 27 | return buffer.getByte(0) == MessageUtil.MAGIC_REQ && buffer.getByte(1) == DCP_BUFFER_ACK_OPCODE; 28 | } 29 | 30 | public static void init(final ByteBuf buffer) { 31 | MessageUtil.initRequest(DCP_BUFFER_ACK_OPCODE, buffer); 32 | } 33 | 34 | public static void opaque(final ByteBuf buffer, int opaque) { 35 | MessageUtil.setOpaque(opaque, buffer); 36 | } 37 | 38 | public static void ackBytes(final ByteBuf buffer, int bytes) { 39 | ByteBuf extras = Unpooled.buffer(4); 40 | MessageUtil.setExtras(extras.writeInt(bytes), buffer); 41 | extras.release(); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/DcpCloseStreamRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | 20 | import static com.couchbase.client.dcp.message.MessageUtil.DCP_STREAM_CLOSE_OPCODE; 21 | 22 | public enum DcpCloseStreamRequest { 23 | ; 24 | 25 | public static boolean is(final ByteBuf buffer) { 26 | return buffer.getByte(0) == MessageUtil.MAGIC_REQ && buffer.getByte(1) == DCP_STREAM_CLOSE_OPCODE; 27 | } 28 | 29 | public static void init(final ByteBuf buffer) { 30 | MessageUtil.initRequest(DCP_STREAM_CLOSE_OPCODE, buffer); 31 | } 32 | 33 | 34 | public static void vbucket(final ByteBuf buffer, final int vbid) { 35 | MessageUtil.setVbucket(vbid, buffer); 36 | } 37 | 38 | public static void opaque(final ByteBuf buffer, int opaque) { 39 | MessageUtil.setOpaque(opaque, buffer); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/DcpCloseStreamResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | 20 | import static com.couchbase.client.dcp.message.MessageUtil.DCP_STREAM_CLOSE_OPCODE; 21 | 22 | public enum DcpCloseStreamResponse { 23 | ; 24 | 25 | public static boolean is(final ByteBuf buffer) { 26 | return buffer.getByte(0) == MessageUtil.MAGIC_RES && buffer.getByte(1) == DCP_STREAM_CLOSE_OPCODE; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/DcpControlRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | 20 | import static com.couchbase.client.dcp.message.MessageUtil.DCP_CONTROL_OPCODE; 21 | 22 | public enum DcpControlRequest { 23 | ; 24 | 25 | /** 26 | * If the given buffer is a {@link DcpControlRequest} message. 27 | */ 28 | public static boolean is(final ByteBuf buffer) { 29 | return buffer.getByte(0) == MessageUtil.MAGIC_REQ && buffer.getByte(1) == DCP_CONTROL_OPCODE; 30 | } 31 | 32 | /** 33 | * Initialize the buffer with all the values needed. 34 | *

35 | * Note that this will implicitly set the flags to "consumer". 36 | */ 37 | public static void init(final ByteBuf buffer) { 38 | MessageUtil.initRequest(DCP_CONTROL_OPCODE, buffer); 39 | } 40 | 41 | public static void key(final String key, final ByteBuf buffer) { 42 | MessageUtil.setKey(key, buffer); 43 | } 44 | 45 | public static void value(final ByteBuf value, final ByteBuf buffer) { 46 | MessageUtil.setContent(value, buffer); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/DcpControlResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | 20 | import static com.couchbase.client.dcp.message.MessageUtil.DCP_CONTROL_OPCODE; 21 | 22 | public enum DcpControlResponse { 23 | ; 24 | 25 | /** 26 | * If the given buffer is a {@link DcpControlResponse} message. 27 | */ 28 | public static boolean is(final ByteBuf buffer) { 29 | return buffer.getByte(0) == MessageUtil.MAGIC_RES && buffer.getByte(1) == DCP_CONTROL_OPCODE; 30 | } 31 | 32 | /** 33 | * Initialize the buffer with all the values needed. 34 | *

35 | * Note that this will implicitly set the flags to "consumer". 36 | */ 37 | public static void init(final ByteBuf buffer) { 38 | MessageUtil.initResponse(DCP_CONTROL_OPCODE, buffer); 39 | } 40 | 41 | public static void key(final String key, final ByteBuf buffer) { 42 | MessageUtil.setKey(key, buffer); 43 | } 44 | 45 | public static void value(final ByteBuf value, final ByteBuf buffer) { 46 | MessageUtil.setContent(value, buffer); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/DcpFailoverLogRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | 20 | import static com.couchbase.client.dcp.message.MessageUtil.DCP_FAILOVER_LOG_OPCODE; 21 | 22 | public enum DcpFailoverLogRequest { 23 | ; 24 | 25 | public static boolean is(final ByteBuf buffer) { 26 | return buffer.getByte(0) == MessageUtil.MAGIC_REQ && buffer.getByte(1) == DCP_FAILOVER_LOG_OPCODE; 27 | } 28 | 29 | public static void init(final ByteBuf buffer) { 30 | MessageUtil.initRequest(DCP_FAILOVER_LOG_OPCODE, buffer); 31 | } 32 | 33 | public static void vbucket(final ByteBuf buffer, final int vbid) { 34 | MessageUtil.setVbucket(vbid, buffer); 35 | } 36 | 37 | public static void opaque(final ByteBuf buffer, int opaque) { 38 | MessageUtil.setOpaque(opaque, buffer); 39 | } 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/DcpFlushRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | 20 | import static com.couchbase.client.dcp.message.MessageUtil.DCP_FLUSH_OPCODE; 21 | 22 | public enum DcpFlushRequest { 23 | ; 24 | 25 | public static boolean is(final ByteBuf buffer) { 26 | return buffer.getByte(0) == MessageUtil.MAGIC_REQ && buffer.getByte(1) == DCP_FLUSH_OPCODE; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/DcpGetPartitionSeqnosRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | 19 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 20 | import com.couchbase.client.core.deps.io.netty.buffer.Unpooled; 21 | 22 | import static com.couchbase.client.dcp.message.MessageUtil.GET_SEQNOS_OPCODE; 23 | 24 | public enum DcpGetPartitionSeqnosRequest { 25 | ; 26 | 27 | public static boolean is(final ByteBuf buffer) { 28 | return buffer.getByte(0) == MessageUtil.MAGIC_REQ && buffer.getByte(1) == GET_SEQNOS_OPCODE; 29 | } 30 | 31 | public static void init(final ByteBuf buffer) { 32 | MessageUtil.initRequest(GET_SEQNOS_OPCODE, buffer); 33 | } 34 | 35 | public static void opaque(final ByteBuf buffer, int opaque) { 36 | MessageUtil.setOpaque(opaque, buffer); 37 | } 38 | 39 | public static void vbucketState(final ByteBuf buffer, VbucketState vbucketState) { 40 | 41 | switch (vbucketState) { 42 | case ANY: 43 | break; 44 | case ACTIVE: 45 | case REPLICA: 46 | case PENDING: 47 | case DEAD: 48 | ByteBuf extras = Unpooled.buffer(4); 49 | MessageUtil.setExtras(extras.writeInt(vbucketState.value()), buffer); 50 | extras.release(); 51 | } 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/DcpGetPartitionSeqnosResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | 19 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 20 | 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | 24 | import static com.couchbase.client.dcp.message.MessageUtil.GET_SEQNOS_OPCODE; 25 | 26 | public enum DcpGetPartitionSeqnosResponse { 27 | ; 28 | 29 | public static boolean is(final ByteBuf buffer) { 30 | return buffer.getByte(0) == MessageUtil.MAGIC_RES && buffer.getByte(1) == GET_SEQNOS_OPCODE; 31 | } 32 | 33 | /** 34 | * @deprecated Please use {@link #parse instead} 35 | */ 36 | @Deprecated 37 | public static int numPairs(final ByteBuf buffer) { 38 | int bodyLength = MessageUtil.getContent(buffer).readableBytes(); 39 | return bodyLength / 10; // one pair is short + long = 10 bytes 40 | } 41 | 42 | public static List parse(final ByteBuf buf) { 43 | List result = new ArrayList<>(); 44 | 45 | ByteBuf content = MessageUtil.getContent(buf); 46 | while (content.isReadable()) { 47 | int partition = content.readShort(); 48 | long seqno = content.readLong(); 49 | result.add(new PartitionAndSeqno(partition, seqno)); 50 | } 51 | 52 | return result; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/DcpNoopRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | 20 | import static com.couchbase.client.dcp.message.MessageUtil.DCP_NOOP_OPCODE; 21 | 22 | public enum DcpNoopRequest { 23 | ; 24 | 25 | public static boolean is(final ByteBuf buffer) { 26 | return buffer.getByte(0) == MessageUtil.MAGIC_REQ && buffer.getByte(1) == DCP_NOOP_OPCODE; 27 | } 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/DcpNoopResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | 20 | import static com.couchbase.client.dcp.message.MessageUtil.DCP_NOOP_OPCODE; 21 | 22 | public enum DcpNoopResponse { 23 | ; 24 | 25 | public static boolean is(final ByteBuf buffer) { 26 | return buffer.getByte(0) == MessageUtil.MAGIC_RES && buffer.getByte(1) == DCP_NOOP_OPCODE; 27 | } 28 | 29 | public static void init(final ByteBuf buffer) { 30 | MessageUtil.initResponse(DCP_NOOP_OPCODE, buffer); 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/DcpOpenConnectionResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | 20 | import static com.couchbase.client.dcp.message.MessageUtil.OPEN_CONNECTION_OPCODE; 21 | 22 | public enum DcpOpenConnectionResponse { 23 | ; 24 | 25 | /** 26 | * If the given buffer is a {@link DcpOpenConnectionResponse} message. 27 | */ 28 | public static boolean is(final ByteBuf buffer) { 29 | return buffer.getByte(0) == MessageUtil.MAGIC_RES && buffer.getByte(1) == OPEN_CONNECTION_OPCODE; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/DcpOpenStreamResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | 20 | import static com.couchbase.client.dcp.message.MessageUtil.DCP_STREAM_REQUEST_OPCODE; 21 | import static com.couchbase.client.dcp.message.ResponseStatus.ROLLBACK_REQUIRED; 22 | 23 | public enum DcpOpenStreamResponse { 24 | ; 25 | 26 | public static boolean is(final ByteBuf buffer) { 27 | return buffer.getByte(0) == MessageUtil.MAGIC_RES && buffer.getByte(1) == DCP_STREAM_REQUEST_OPCODE; 28 | } 29 | 30 | public static int vbucket(ByteBuf buffer) { 31 | return MessageUtil.getVbucket(buffer); 32 | } 33 | 34 | public static long rollbackSeqno(ByteBuf buffer) { 35 | if (MessageUtil.getResponseStatus(buffer) == ROLLBACK_REQUIRED) { 36 | return MessageUtil.getContent(buffer).getLong(0); 37 | } else { 38 | throw new IllegalStateException("Rollback sequence number accessible only for ROLLBACK (0x23) status code"); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/DcpSeqnoAdvancedRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.message; 18 | 19 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 20 | 21 | public class DcpSeqnoAdvancedRequest { 22 | private DcpSeqnoAdvancedRequest() { 23 | throw new AssertionError("not instantiable"); 24 | } 25 | 26 | public static boolean is(ByteBuf event) { 27 | return event.getByte(0) == MessageUtil.MAGIC_REQ 28 | && event.getByte(1) == MessageUtil.DCP_SEQNO_ADVANCED_OPCODE; 29 | } 30 | 31 | public static long getSeqno(ByteBuf event) { 32 | return MessageUtil.getExtras(event).readLong(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/DcpSnapshotMarkerRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | 20 | import java.util.Set; 21 | 22 | import static com.couchbase.client.dcp.message.MessageUtil.DCP_SNAPSHOT_MARKER_OPCODE; 23 | 24 | public enum DcpSnapshotMarkerRequest { 25 | ; 26 | 27 | public static boolean is(final ByteBuf buffer) { 28 | return buffer.getByte(0) == MessageUtil.MAGIC_REQ && buffer.getByte(1) == DCP_SNAPSHOT_MARKER_OPCODE; 29 | } 30 | 31 | public static Set flags(final ByteBuf buffer) { 32 | return SnapshotMarkerFlag.decode(flagsAsInt(buffer)); 33 | } 34 | 35 | public static int flagsAsInt(final ByteBuf buffer) { 36 | return MessageUtil.getExtras(buffer).getInt(16); 37 | } 38 | 39 | public static long startSeqno(final ByteBuf buffer) { 40 | return MessageUtil.getExtras(buffer).getLong(0); 41 | } 42 | 43 | public static long endSeqno(final ByteBuf buffer) { 44 | return MessageUtil.getExtras(buffer).getLong(8); 45 | } 46 | 47 | public static String toString(final ByteBuf buffer) { 48 | return "SnapshotMarker [vbid: " + partition(buffer) 49 | + ", flags: " + String.format("0x%02x", flagsAsInt(buffer)) 50 | + ", start: " + startSeqno(buffer) 51 | + ", end: " + endSeqno(buffer) 52 | + "]"; 53 | } 54 | 55 | public static int partition(final ByteBuf buffer) { 56 | return MessageUtil.getVbucket(buffer); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/DcpSnapshotMarkerResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | 20 | import static com.couchbase.client.dcp.message.MessageUtil.DCP_SNAPSHOT_MARKER_OPCODE; 21 | 22 | public enum DcpSnapshotMarkerResponse { 23 | ; 24 | 25 | public static boolean is(final ByteBuf buffer) { 26 | return buffer.getByte(0) == MessageUtil.MAGIC_RES && buffer.getByte(1) == DCP_SNAPSHOT_MARKER_OPCODE; 27 | } 28 | 29 | public static void init(final ByteBuf buffer) { 30 | MessageUtil.initResponse(DCP_SNAPSHOT_MARKER_OPCODE, buffer); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/DcpStreamEndMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | 20 | import static com.couchbase.client.dcp.message.MessageUtil.DCP_STREAM_END_OPCODE; 21 | 22 | public enum DcpStreamEndMessage { 23 | ; 24 | 25 | public static boolean is(final ByteBuf buffer) { 26 | return buffer.getByte(0) == MessageUtil.MAGIC_REQ && buffer.getByte(1) == DCP_STREAM_END_OPCODE; 27 | } 28 | 29 | public static int vbucket(final ByteBuf buffer) { 30 | return MessageUtil.getVbucket(buffer); 31 | } 32 | 33 | public static StreamEndReason reason(final ByteBuf buffer) { 34 | int flags = MessageUtil.getExtras(buffer).getInt(0); 35 | return StreamEndReason.of(flags); 36 | } 37 | 38 | public static String getReasonAsString(final ByteBuf buffer) { 39 | int reasonCode = MessageUtil.getExtras(buffer).getInt(0); 40 | try { 41 | return StreamEndReason.of(reasonCode).name(); 42 | } catch (IllegalArgumentException e) { 43 | return String.valueOf(reasonCode); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/DcpSystemEventRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.message; 18 | 19 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 20 | 21 | import static com.couchbase.client.dcp.message.MessageUtil.DCP_SYSTEM_EVENT_OPCODE; 22 | import static com.couchbase.client.dcp.message.MessageUtil.getExtras; 23 | 24 | public class DcpSystemEventRequest { 25 | public static boolean is(final ByteBuf buffer) { 26 | return buffer.getByte(0) == MessageUtil.MAGIC_REQ && buffer.getByte(1) == DCP_SYSTEM_EVENT_OPCODE; 27 | } 28 | 29 | public static long getSeqno(final ByteBuf buffer) { 30 | return getExtras(buffer).readLong(); 31 | } 32 | 33 | public static int getId(final ByteBuf buffer) { 34 | return getExtras(buffer).skipBytes(8).readInt(); 35 | } 36 | 37 | public static int getVersion(final ByteBuf buffer) { 38 | return getExtras(buffer).skipBytes(8).skipBytes(4).readUnsignedByte(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/PartitionAndSeqno.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.message; 18 | 19 | import java.util.Objects; 20 | 21 | /** 22 | * An immutable pair consisting of a partition and an associated sequence number. 23 | */ 24 | public class PartitionAndSeqno { 25 | private final int partition; 26 | private final long seqno; 27 | 28 | public PartitionAndSeqno(int partition, long seqno) { 29 | this.partition = partition; 30 | this.seqno = seqno; 31 | } 32 | 33 | public int partition() { 34 | return partition; 35 | } 36 | 37 | public long seqno() { 38 | return seqno; 39 | } 40 | 41 | @Override 42 | public boolean equals(Object o) { 43 | if (this == o) { 44 | return true; 45 | } 46 | if (o == null || getClass() != o.getClass()) { 47 | return false; 48 | } 49 | PartitionAndSeqno that = (PartitionAndSeqno) o; 50 | return partition == that.partition && 51 | seqno == that.seqno; 52 | } 53 | 54 | @Override 55 | public int hashCode() { 56 | return Objects.hash(partition, seqno); 57 | } 58 | 59 | @Override 60 | public String toString() { 61 | return "PartitionAndSeqno{" + 62 | "partition=" + partition + 63 | ", seqno=" + seqno + 64 | '}'; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/RollbackMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | 20 | import static com.couchbase.client.dcp.message.MessageUtil.INTERNAL_ROLLBACK_OPCODE; 21 | 22 | public enum RollbackMessage { 23 | ; 24 | 25 | public static boolean is(final ByteBuf buffer) { 26 | return buffer.getByte(0) == MessageUtil.MAGIC_INT && buffer.getByte(1) == INTERNAL_ROLLBACK_OPCODE; 27 | } 28 | 29 | public static void init(ByteBuf buffer, int vbid, long seqno) { 30 | buffer.writeByte(MessageUtil.MAGIC_INT); 31 | buffer.writeByte(MessageUtil.INTERNAL_ROLLBACK_OPCODE); 32 | buffer.writeShort(vbid); 33 | buffer.writeLong(seqno); 34 | } 35 | 36 | public static int vbucket(ByteBuf buffer) { 37 | return buffer.getShort(2); 38 | } 39 | 40 | public static long seqno(ByteBuf buffer) { 41 | return buffer.getLong(4); 42 | } 43 | 44 | public static String toString(ByteBuf buffer) { 45 | return "Rollback [vbid: " + vbucket(buffer) + ", seqno: " + seqno(buffer) + "]"; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/SaslAuthRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | 20 | import static com.couchbase.client.dcp.message.MessageUtil.SASL_AUTH_OPCODE; 21 | 22 | public enum SaslAuthRequest { 23 | ; 24 | 25 | /** 26 | * If the given buffer is a {@link SaslAuthRequest} message. 27 | */ 28 | public static boolean is(final ByteBuf buffer) { 29 | return buffer.getByte(0) == MessageUtil.MAGIC_REQ && buffer.getByte(1) == SASL_AUTH_OPCODE; 30 | } 31 | 32 | /** 33 | * Initialize the buffer with all the values needed. 34 | */ 35 | public static void init(final ByteBuf buffer) { 36 | MessageUtil.initRequest(SASL_AUTH_OPCODE, buffer); 37 | } 38 | 39 | /** 40 | * Sets the selected mechanism. 41 | */ 42 | public static void mechanism(String mechanism, ByteBuf buffer) { 43 | MessageUtil.setKey(mechanism, buffer); 44 | } 45 | 46 | /** 47 | * Sets the challenge response payload. 48 | */ 49 | public static void challengeResponse(byte[] challengeResponse, ByteBuf buffer) { 50 | MessageUtil.setContent(challengeResponse, buffer); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/SaslAuthResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | 20 | import static com.couchbase.client.dcp.message.MessageUtil.SASL_AUTH_OPCODE; 21 | 22 | public enum SaslAuthResponse { 23 | ; 24 | 25 | /** 26 | * If the given buffer is a {@link SaslAuthResponse} message. 27 | */ 28 | public static boolean is(final ByteBuf buffer) { 29 | return buffer.getByte(0) == MessageUtil.MAGIC_RES && buffer.getByte(1) == SASL_AUTH_OPCODE; 30 | } 31 | 32 | /** 33 | * Returns the server challenge. 34 | */ 35 | public static byte[] challenge(final ByteBuf buffer) { 36 | return MessageUtil.getContentAsByteArray(buffer); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/SaslListMechsRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | 20 | import static com.couchbase.client.dcp.message.MessageUtil.SASL_LIST_MECHS_OPCODE; 21 | 22 | public enum SaslListMechsRequest { 23 | ; 24 | 25 | /** 26 | * If the given buffer is a {@link SaslListMechsRequest} message. 27 | */ 28 | public static boolean is(final ByteBuf buffer) { 29 | return buffer.getByte(0) == MessageUtil.MAGIC_REQ && buffer.getByte(1) == SASL_LIST_MECHS_OPCODE; 30 | } 31 | 32 | /** 33 | * Initialize the buffer with all the values needed. 34 | */ 35 | public static void init(final ByteBuf buffer) { 36 | MessageUtil.initRequest(SASL_LIST_MECHS_OPCODE, buffer); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/SaslListMechsResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | 20 | import java.util.Arrays; 21 | import java.util.List; 22 | 23 | import static com.couchbase.client.dcp.message.MessageUtil.SASL_LIST_MECHS_OPCODE; 24 | import static java.util.Collections.emptyList; 25 | 26 | public enum SaslListMechsResponse { 27 | ; 28 | 29 | /** 30 | * If the given buffer is a {@link SaslListMechsResponse} message. 31 | */ 32 | public static boolean is(final ByteBuf buffer) { 33 | return buffer.getByte(0) == MessageUtil.MAGIC_RES && buffer.getByte(1) == SASL_LIST_MECHS_OPCODE; 34 | } 35 | 36 | /** 37 | * Extracts the supported SASL mechanisms as a string array. 38 | * 39 | * @param buffer the buffer to extract from. 40 | * @return the array of supported mechs, or an empty array if none found. 41 | */ 42 | public static List supportedMechs(final ByteBuf buffer) { 43 | String spaceDelimitedMechanisms = MessageUtil.getContentAsString(buffer); 44 | return spaceDelimitedMechanisms.isEmpty() ? emptyList() : Arrays.asList(spaceDelimitedMechanisms.split(" ")); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/SaslStepRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | 20 | import static com.couchbase.client.dcp.message.MessageUtil.SASL_STEP_OPCODE; 21 | 22 | public enum SaslStepRequest { 23 | ; 24 | 25 | /** 26 | * If the given buffer is a {@link SaslStepRequest} message. 27 | */ 28 | public static boolean is(final ByteBuf buffer) { 29 | return buffer.getByte(0) == MessageUtil.MAGIC_REQ && buffer.getByte(1) == SASL_STEP_OPCODE; 30 | } 31 | 32 | /** 33 | * Initialize the buffer with all the values needed. 34 | */ 35 | public static void init(final ByteBuf buffer) { 36 | MessageUtil.initRequest(SASL_STEP_OPCODE, buffer); 37 | } 38 | 39 | /** 40 | * Sets the selected mechanism. 41 | */ 42 | public static void mechanism(String mechanism, ByteBuf buffer) { 43 | MessageUtil.setKey(mechanism, buffer); 44 | } 45 | 46 | /** 47 | * Sets the challenge response payload. 48 | */ 49 | public static void challengeResponse(byte[] challengeResponse, ByteBuf buffer) { 50 | MessageUtil.setContent(challengeResponse, buffer); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/SaslStepResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | 20 | import static com.couchbase.client.dcp.message.MessageUtil.SASL_STEP_OPCODE; 21 | 22 | public enum SaslStepResponse { 23 | ; 24 | 25 | /** 26 | * If the given buffer is a {@link SaslStepResponse} message. 27 | */ 28 | public static boolean is(final ByteBuf buffer) { 29 | return buffer.getByte(0) == MessageUtil.MAGIC_RES && buffer.getByte(1) == SASL_STEP_OPCODE; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/VbucketState.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | public enum VbucketState { 19 | /** 20 | * Any live state (except DEAD). 21 | */ 22 | ANY(0), 23 | /** 24 | * Actively servicing a partition. 25 | */ 26 | ACTIVE(1), 27 | /** 28 | * Servicing a partition as a replica only. 29 | */ 30 | REPLICA(2), 31 | /** 32 | * Pending active. 33 | */ 34 | PENDING(3), 35 | /** 36 | * Not in use, pending deletion. 37 | */ 38 | DEAD(4); 39 | 40 | private final int value; 41 | 42 | VbucketState(int value) { 43 | this.value = value; 44 | } 45 | 46 | public int value() { 47 | return value; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/message/VersionRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | 20 | public enum VersionRequest { 21 | ; 22 | 23 | public static void init(ByteBuf buffer) { 24 | MessageUtil.initRequest(MessageUtil.VERSION_OPCODE, buffer); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/metrics/MetricsContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.metrics; 18 | 19 | import io.micrometer.core.instrument.MeterRegistry; 20 | import io.micrometer.core.instrument.Tags; 21 | 22 | import static java.util.Objects.requireNonNull; 23 | 24 | public class MetricsContext { 25 | private final MeterRegistry registry; 26 | private final String prefix; 27 | private final Tags tags; 28 | 29 | public MetricsContext(MeterRegistry registry, String prefix) { 30 | this(registry, prefix, Tags.empty()); 31 | } 32 | 33 | public MetricsContext(MeterRegistry registry, String prefix, Tags tags) { 34 | this.registry = requireNonNull(registry); 35 | this.prefix = prefix.isEmpty() || prefix.endsWith(".") ? prefix : prefix + "."; 36 | this.tags = requireNonNull(tags); 37 | } 38 | 39 | public MeterRegistry registry() { 40 | return registry; 41 | } 42 | 43 | public MetricsContext withTags(Tags tags) { 44 | return new MetricsContext(registry, prefix, Tags.concat(this.tags, tags)); 45 | } 46 | 47 | public ActionCounter.Builder newActionCounter(String name) { 48 | return ActionCounter.builder(registry, prefix + name) 49 | .tags(tags); 50 | } 51 | 52 | public EventCounter.Builder newEventCounter(String name) { 53 | return EventCounter.builder(registry, prefix + name) 54 | .tags(tags); 55 | } 56 | 57 | public ActionTimer.Builder newActionTimer(String name) { 58 | return ActionTimer.builder(registry, name) 59 | .tags(tags); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/state/StateFormat.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.state; 17 | 18 | /** 19 | * Defines the support import/export formats for a {@link SessionState}. 20 | * 21 | * @deprecated See {@link com.couchbase.client.dcp.Client#recoverState} for details. 22 | */ 23 | @Deprecated 24 | public enum StateFormat { 25 | JSON 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/state/json/SessionStateSerializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.state.json; 17 | 18 | import com.couchbase.client.core.deps.com.fasterxml.jackson.core.JsonGenerator; 19 | import com.couchbase.client.core.deps.com.fasterxml.jackson.databind.JsonSerializer; 20 | import com.couchbase.client.core.deps.com.fasterxml.jackson.databind.SerializerProvider; 21 | import com.couchbase.client.dcp.state.PartitionState; 22 | import com.couchbase.client.dcp.state.SessionState; 23 | 24 | import java.io.IOException; 25 | 26 | /** 27 | * Jackson JSON serializer for {@link SessionState} and {@link PartitionState}. 28 | * 29 | * @author Michael Nitschinger 30 | * @since 1.0.0 31 | */ 32 | public class SessionStateSerializer extends JsonSerializer { 33 | 34 | @Override 35 | public void serialize(SessionState ss, final JsonGenerator gen, final SerializerProvider serializers) 36 | throws IOException { 37 | gen.writeStartObject(); 38 | 39 | gen.writeFieldName("v"); 40 | gen.writeNumber(SessionState.CURRENT_VERSION); 41 | 42 | gen.writeFieldName("ps"); 43 | gen.writeStartArray(); 44 | ss.foreachPartition(partitionState -> { 45 | try { 46 | gen.writeObject(partitionState); 47 | } catch (Exception ex) { 48 | throw new RuntimeException("Could not serialize PartitionState to JSON: " + partitionState, ex); 49 | } 50 | }); 51 | gen.writeEndArray(); 52 | 53 | gen.writeEndObject(); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/transport/netty/ChannelFlowController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.transport.netty; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | import com.couchbase.client.dcp.Client; 20 | 21 | public interface ChannelFlowController { 22 | /** 23 | * Acknowledge bytes read if DcpControl.Names.CONNECTION_BUFFER_SIZE is set on bootstrap. 24 | *

25 | * Note that acknowledgement will be stored but most likely not sent to the server immediately to save network 26 | * overhead. Instead, depending on the value set through {@link Client.Builder#bufferAckWatermark(int)} in percent 27 | * the client will automatically determine when to send the message (when the watermark is reached). 28 | *

29 | * This method can always be called even if not enabled, if not enabled on bootstrap it will short-circuit. 30 | * 31 | * @param message the buffer to acknowledge. 32 | */ 33 | void ack(ByteBuf message); 34 | 35 | void ack(int numBytes); 36 | 37 | /** 38 | * A flow controller that doesn't do anything. 39 | */ 40 | ChannelFlowController dummy = new ChannelFlowController() { 41 | @Override 42 | public void ack(ByteBuf message) { 43 | } 44 | 45 | @Override 46 | public void ack(int numBytes) { 47 | 48 | } 49 | }; 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/transport/netty/DcpResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.transport.netty; 18 | 19 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 20 | import com.couchbase.client.dcp.message.ResponseStatus; 21 | 22 | import static com.couchbase.client.dcp.message.MessageUtil.getResponseStatus; 23 | import static java.util.Objects.requireNonNull; 24 | 25 | public class DcpResponse { 26 | private final ByteBuf buffer; 27 | 28 | // cache the status so it can still be retrieved after the buffer is released 29 | private final ResponseStatus status; 30 | 31 | public DcpResponse(ByteBuf buffer) { 32 | this.buffer = requireNonNull(buffer); 33 | this.status = getResponseStatus(buffer); 34 | } 35 | 36 | public ByteBuf buffer() { 37 | return buffer; 38 | } 39 | 40 | public ResponseStatus status() { 41 | return status; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/transport/netty/DcpResponseListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.transport.netty; 18 | 19 | import com.couchbase.client.core.deps.io.netty.util.concurrent.Future; 20 | import com.couchbase.client.core.deps.io.netty.util.concurrent.GenericFutureListener; 21 | 22 | 23 | /** 24 | * Type alias. 25 | */ 26 | public interface DcpResponseListener extends GenericFutureListener> { 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/transport/netty/HandshakeDeadlineEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.transport.netty; 18 | 19 | /** 20 | * A user event indicating the connection should be failed 21 | * if the handshake is not yet complete. 22 | */ 23 | public class HandshakeDeadlineEvent { 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/util/AtomicBooleanArray.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.util; 18 | 19 | import java.util.concurrent.atomic.AtomicIntegerArray; 20 | 21 | /** 22 | * A {@code boolean} array in which elements may be updated atomically. 23 | */ 24 | public class AtomicBooleanArray { 25 | private final AtomicIntegerArray array; 26 | 27 | /** 28 | * Creates a new AtomicBooleanArray of the given length, with all 29 | * elements initially false. 30 | * 31 | * @param length the length of the array 32 | */ 33 | public AtomicBooleanArray(int length) { 34 | // A more efficient implementation could pack 32 booleans into a each integer, 35 | // but for now let's do something simple so there's nowhere for bugs to hide. 36 | array = new AtomicIntegerArray(length); 37 | } 38 | 39 | public boolean get(int index) { 40 | return array.get(index) == 1; 41 | } 42 | 43 | public void set(int index, boolean value) { 44 | array.set(index, value ? 1 : 0); 45 | } 46 | 47 | public int length() { 48 | return array.length(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/couchbase/client/dcp/util/MathUtils.java: -------------------------------------------------------------------------------- 1 | package com.couchbase.client.dcp.util; 2 | 3 | /** 4 | * Various math utility methods, also backports from later JDK versions. 5 | * 6 | * @author Sergey Avseyev 7 | * @since 0.10.0 8 | */ 9 | public class MathUtils { 10 | /** 11 | * Compares two numbers as unsigned 64-bit integers. 12 | * 13 | * @param x left operand 14 | * @param y right operand 15 | * @return true if x is less than y 16 | */ 17 | public static boolean lessThanUnsigned(long x, long y) { 18 | return Long.compareUnsigned(x, y) < 0; 19 | } 20 | 21 | /** 22 | * Backport of {@code Long.compare} from Java 7. 23 | * 24 | * @deprecated In favor of {@link Long#compare(long, long)} 25 | */ 26 | @Deprecated 27 | public static int compareLong(long x, long y) { 28 | return Long.compare(x, y); 29 | } 30 | 31 | /** 32 | * Backport of {@code Long.compareUnsigned} from Java 8. 33 | * 34 | * @deprecated In favor of {@link Long#compareUnsigned(long, long)} 35 | */ 36 | @Deprecated 37 | public static int compareUnsignedLong(long x, long y) { 38 | return Long.compareUnsigned(x, y); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/resources/com/couchbase/client/dcp/version.properties: -------------------------------------------------------------------------------- 1 | projectVersion=${project.version} 2 | -------------------------------------------------------------------------------- /src/test/java/com/couchbase/client/dcp/DefaultConnectionNameGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.couchbase.client.dcp; 2 | 3 | import com.couchbase.client.dcp.core.utils.DefaultObjectMapper; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.util.Map; 7 | 8 | import static org.junit.jupiter.api.Assertions.assertEquals; 9 | 10 | public class DefaultConnectionNameGeneratorTest { 11 | 12 | @Test 13 | void connectionNameLimitEnforced() throws Exception { 14 | final String fiveHundredChars = repeat("x", 500); 15 | 16 | final DefaultConnectionNameGenerator generator = DefaultConnectionNameGenerator.forProduct( 17 | "MyProduct", "1.0", fiveHundredChars); 18 | 19 | final String connectionName = generator.name(); 20 | assertEquals(200, connectionName.length()); 21 | } 22 | 23 | @Test 24 | void userAgentTruncationAccountsForJsonEscapes() throws Exception { 25 | final String fiveHundredQuotes = repeat("\"", 500); 26 | 27 | final DefaultConnectionNameGenerator generator = DefaultConnectionNameGenerator.forProduct( 28 | "MyProduct", "1.0", fiveHundredQuotes); 29 | 30 | final String connectionName = generator.name(); 31 | assertEquals(199, connectionName.length()); 32 | 33 | final Map decoded = DefaultObjectMapper.readValueAsMap(connectionName); 34 | final String userAgent = (String) decoded.get("a"); 35 | final String expectedQuotes = repeat("\"", 68); 36 | final String expected = "MyProduct/1.0 (" + expectedQuotes; 37 | assertEquals(expected, userAgent); 38 | } 39 | 40 | private static String repeat(String s, int count) { 41 | final StringBuilder sb = new StringBuilder(); 42 | for (int i = 0; i < count; i++) { 43 | sb.append(s); 44 | } 45 | return sb.toString(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/com/couchbase/client/dcp/core/lang/TupleTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.core.lang; 17 | 18 | import org.junit.jupiter.api.Test; 19 | 20 | import static org.junit.jupiter.api.Assertions.assertEquals; 21 | 22 | public class TupleTest { 23 | 24 | @Test 25 | void shouldCreateWithTwoValues() throws Exception { 26 | Tuple2 tuple = Tuple.create("value1", 2); 27 | assertEquals("value1", tuple.value1()); 28 | assertEquals(2, (long) tuple.value2()); 29 | 30 | Tuple2 swapped = tuple.swap(); 31 | assertEquals("value1", swapped.value2()); 32 | assertEquals(2, (long) swapped.value1()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/com/couchbase/client/dcp/core/state/AbstractStateMachineTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.core.state; 17 | 18 | import org.junit.jupiter.api.Test; 19 | 20 | import static org.junit.jupiter.api.Assertions.assertEquals; 21 | import static org.junit.jupiter.api.Assertions.assertFalse; 22 | import static org.junit.jupiter.api.Assertions.assertTrue; 23 | 24 | /** 25 | * Verifies the functionality for the {@link AbstractStateMachine}. 26 | */ 27 | public class AbstractStateMachineTest { 28 | 29 | @Test 30 | void shouldBeInInitialState() { 31 | SimpleStateMachine sm = new SimpleStateMachine(LifecycleState.DISCONNECTED); 32 | assertEquals(LifecycleState.DISCONNECTED, sm.state()); 33 | assertTrue(sm.isState(LifecycleState.DISCONNECTED)); 34 | assertFalse(sm.isState(LifecycleState.CONNECTING)); 35 | } 36 | 37 | @Test 38 | void shouldTransitionIntoDifferentState() { 39 | SimpleStateMachine sm = new SimpleStateMachine(LifecycleState.DISCONNECTED); 40 | 41 | sm.transitionState(LifecycleState.CONNECTING); 42 | assertEquals(LifecycleState.CONNECTING, sm.state()); 43 | assertTrue(sm.isState(LifecycleState.CONNECTING)); 44 | } 45 | 46 | static class SimpleStateMachine extends AbstractStateMachine { 47 | 48 | public SimpleStateMachine(LifecycleState initialState) { 49 | super(initialState); 50 | } 51 | 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/test/java/com/couchbase/client/dcp/core/time/DelayTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.core.time; 17 | 18 | import org.junit.jupiter.api.Test; 19 | 20 | import java.util.concurrent.TimeUnit; 21 | 22 | import static org.junit.jupiter.api.Assertions.assertEquals; 23 | 24 | public class DelayTest { 25 | 26 | @Test 27 | void shouldBuildFixedDelay() { 28 | Delay delay = Delay.fixed(5, TimeUnit.MICROSECONDS); 29 | assertEquals(TimeUnit.MICROSECONDS, delay.unit()); 30 | assertEquals(5, delay.calculate(10)); 31 | } 32 | 33 | @Test 34 | void shouldBuildLinearDelay() { 35 | Delay delay = Delay.linear(TimeUnit.HOURS); 36 | assertEquals(TimeUnit.HOURS, delay.unit()); 37 | assertEquals(10, delay.calculate(10)); 38 | } 39 | 40 | @Test 41 | void shouldBuildExponentialDelay() { 42 | Delay delay = Delay.exponential(TimeUnit.SECONDS); 43 | assertEquals(TimeUnit.SECONDS, delay.unit()); 44 | assertEquals(512, delay.calculate(10)); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/com/couchbase/client/dcp/core/time/FixedDelayTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.core.time; 17 | 18 | import org.junit.jupiter.api.Test; 19 | 20 | import java.util.concurrent.TimeUnit; 21 | 22 | import static org.junit.jupiter.api.Assertions.assertEquals; 23 | 24 | public class FixedDelayTest { 25 | 26 | @Test 27 | void shouldCalculateFixedDelay() { 28 | Delay fixedDelay = new FixedDelay(3, TimeUnit.SECONDS); 29 | 30 | assertEquals(3, fixedDelay.calculate(1)); 31 | assertEquals(3, fixedDelay.calculate(2)); 32 | assertEquals(3, fixedDelay.calculate(3)); 33 | 34 | assertEquals("FixedDelay{3 SECONDS}", fixedDelay.toString()); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/com/couchbase/client/dcp/message/StreamEndReasonTest.java: -------------------------------------------------------------------------------- 1 | package com.couchbase.client.dcp.message; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | import static org.junit.jupiter.api.Assertions.assertSame; 7 | 8 | public class StreamEndReasonTest { 9 | @Test 10 | void canCreateUnknown() { 11 | final int unknownCode = Integer.MAX_VALUE; 12 | StreamEndReason unknown = StreamEndReason.of(unknownCode); 13 | StreamEndReason sameAgain = StreamEndReason.of(unknownCode); 14 | assertEquals(unknown, sameAgain); 15 | assertEquals(unknownCode, unknown.value()); 16 | } 17 | 18 | @Test 19 | void canCompareRecognizedUsingIdentity() { 20 | assertSame(StreamEndReason.of(0), StreamEndReason.OK); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/com/couchbase/client/dcp/message/control/OpenConnectionRequestTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.message.control; 17 | 18 | import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf; 19 | import com.couchbase.client.core.deps.io.netty.buffer.Unpooled; 20 | import com.couchbase.client.dcp.message.DcpOpenConnectionRequest; 21 | import org.junit.jupiter.api.Test; 22 | 23 | import static java.nio.charset.StandardCharsets.UTF_8; 24 | import static java.util.Collections.emptySet; 25 | import static org.junit.jupiter.api.Assertions.assertEquals; 26 | import static org.junit.jupiter.api.Assertions.assertFalse; 27 | import static org.junit.jupiter.api.Assertions.assertTrue; 28 | 29 | public class OpenConnectionRequestTest { 30 | 31 | @Test 32 | void testInit() { 33 | ByteBuf buffer = Unpooled.buffer(); 34 | assertFalse(DcpOpenConnectionRequest.is(buffer)); 35 | 36 | DcpOpenConnectionRequest.init(buffer, emptySet()); 37 | 38 | assertEquals(32, buffer.writerIndex()); 39 | assertTrue(DcpOpenConnectionRequest.is(buffer)); 40 | } 41 | 42 | @Test 43 | void testSetConnectionName() { 44 | ByteBuf buffer = Unpooled.buffer(); 45 | DcpOpenConnectionRequest.init(buffer, emptySet()); 46 | 47 | DcpOpenConnectionRequest.connectionName(buffer, "name"); 48 | 49 | assertEquals("name", DcpOpenConnectionRequest.connectionName(buffer).toString(UTF_8)); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/test/java/com/couchbase/client/dcp/perfrunner/GenericUri.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.couchbase.client.dcp.perfrunner; 18 | 19 | import java.util.regex.Matcher; 20 | import java.util.regex.Pattern; 21 | 22 | class GenericUri { 23 | // From https://tools.ietf.org/html/rfc3986#appendix-B 24 | private static final Pattern URI_PATTERN = Pattern.compile( 25 | "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"); 26 | 27 | private final String scheme; 28 | private final String authority; 29 | private final String path; 30 | private final String query; 31 | private final String fragment; 32 | 33 | GenericUri(String uri) throws IllegalArgumentException { 34 | Matcher m = URI_PATTERN.matcher(uri); 35 | if (!m.matches()) { 36 | throw new IllegalArgumentException("Failed to parse URI: " + uri); 37 | } 38 | this.scheme = m.group(2); 39 | this.authority = m.group(4); 40 | this.path = m.group(5); 41 | this.query = m.group(7); 42 | this.fragment = m.group(9); 43 | } 44 | 45 | public String scheme() { 46 | return scheme; 47 | } 48 | 49 | public String authority() { 50 | return authority; 51 | } 52 | 53 | public String path() { 54 | return path; 55 | } 56 | 57 | public String query() { 58 | return query; 59 | } 60 | 61 | public String fragment() { 62 | return fragment; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/test/java/com/couchbase/client/dcp/state/SessionStateRollbackToPositionTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.state; 17 | 18 | import com.couchbase.client.dcp.highlevel.SnapshotMarker; 19 | import org.junit.jupiter.api.Test; 20 | 21 | import java.util.Arrays; 22 | 23 | import static java.util.Collections.singletonList; 24 | import static org.junit.jupiter.api.Assertions.assertEquals; 25 | 26 | 27 | public class SessionStateRollbackToPositionTest { 28 | 29 | @Test 30 | void rollbackToPosition() throws Exception { 31 | // Populate a session state with dummy data for a single partition 32 | final SessionState sessionState = new SessionState(); 33 | PartitionState partitionState = new PartitionState(); 34 | partitionState.setFailoverLog(Arrays.asList( 35 | new FailoverLogEntry(1, 345), 36 | new FailoverLogEntry(5, 12345), 37 | new FailoverLogEntry(-1L, 4567))); // seqnos are unsigned, so -1 is max value 38 | partitionState.setStartSeqno(1, new SnapshotMarker(2, 3)); 39 | partitionState.setEndSeqno(1000); 40 | sessionState.set(0, partitionState); 41 | 42 | sessionState.rollbackToPosition(0, 1L); 43 | assertEquals(1, partitionState.getStartSeqno()); 44 | assertEquals(1, partitionState.getSnapshotStartSeqno()); 45 | assertEquals(1, partitionState.getSnapshotEndSeqno()); 46 | assertEquals(singletonList(new FailoverLogEntry(1, 345)), partitionState.getFailoverLog()); 47 | } 48 | 49 | } 50 | 51 | -------------------------------------------------------------------------------- /src/test/java/com/couchbase/client/dcp/state/json/SessionStateDeserializerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Couchbase, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.couchbase.client.dcp.state.json; 17 | 18 | import com.couchbase.client.dcp.state.FailoverLogEntry; 19 | import com.couchbase.client.dcp.state.PartitionState; 20 | import com.couchbase.client.dcp.state.SessionState; 21 | import org.junit.jupiter.api.Test; 22 | 23 | import static java.nio.charset.StandardCharsets.UTF_8; 24 | import static org.junit.jupiter.api.Assertions.assertEquals; 25 | 26 | public class SessionStateDeserializerTest { 27 | @Test 28 | void deserialize() throws Exception { 29 | SessionState sessionState = new SessionState(); 30 | 31 | String json = "{\"v\":1,\"ps\":[{\"flog\":[{\"seqno\":5,\"uuid\":12345}],\"ss\":1,\"es\":1000,\"sss\":2,\"ses\":3}]}"; 32 | sessionState.setFromJson(json.getBytes(UTF_8)); 33 | 34 | PartitionState partitionState = sessionState.get(0); 35 | 36 | assertEquals(1, partitionState.getFailoverLog().size()); 37 | FailoverLogEntry failoverLogEntry = partitionState.getFailoverLog().get(0); 38 | assertEquals(5, failoverLogEntry.getSeqno()); 39 | assertEquals(12345, failoverLogEntry.getUuid()); 40 | 41 | assertEquals(1, partitionState.getStartSeqno()); 42 | assertEquals(1000, partitionState.getEndSeqno()); 43 | assertEquals(2, partitionState.getSnapshotStartSeqno()); 44 | assertEquals(3, partitionState.getSnapshotEndSeqno()); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/com/couchbase/client/dcp/util/AdaptiveDelayTest.java: -------------------------------------------------------------------------------- 1 | package com.couchbase.client.dcp.util; 2 | 3 | import com.couchbase.client.dcp.core.time.Delay; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.time.Duration; 7 | 8 | import static java.util.concurrent.TimeUnit.MILLISECONDS; 9 | import static java.util.concurrent.TimeUnit.SECONDS; 10 | import static org.junit.jupiter.api.Assertions.assertEquals; 11 | 12 | public class AdaptiveDelayTest { 13 | 14 | private static class TestClock implements AdaptiveDelay.TimeProvider { 15 | private long nanos; 16 | 17 | @Override 18 | public long nanoTime() { 19 | return nanos; 20 | } 21 | 22 | void advance(Duration d) { 23 | this.nanos += d.toNanos(); 24 | } 25 | } 26 | 27 | @Test 28 | void startsCool() { 29 | final AdaptiveDelay adaptiveDelay = new AdaptiveDelay(Delay.fixed(5, SECONDS), Duration.ofSeconds(10)); 30 | assertEquals(0, adaptiveDelay.calculate().toNanos()); 31 | } 32 | 33 | @Test 34 | void cooldownEnforced() { 35 | final TestClock clock = new TestClock(); 36 | clock.advance(Duration.ofSeconds(-1)); // nanoTime can be negative, so start here 37 | 38 | final AdaptiveDelay adaptiveDelay = new AdaptiveDelay( 39 | Delay.linear(MILLISECONDS, 3, 1, 1), Duration.ofSeconds(1), clock); 40 | 41 | for (int i = 0; i < 3; i++) { 42 | assertEquals(0, adaptiveDelay.calculate().toMillis()); 43 | assertEquals(1, adaptiveDelay.calculate().toMillis()); 44 | 45 | clock.advance(Duration.ofMillis(500)); // not enough to reset cooldown 46 | assertEquals(2, adaptiveDelay.calculate().toMillis()); 47 | 48 | // cooldown expiry is calculated to include the previous delay, 49 | // so this isn't enough to reset the cooldown either. 50 | clock.advance(Duration.ofSeconds(1)); 51 | 52 | assertEquals(3, adaptiveDelay.calculate().toMillis()); 53 | assertEquals(3, adaptiveDelay.calculate().toMillis()); // upper bound reached 54 | 55 | clock.advance(Duration.ofSeconds(1).plusMillis(3)); // reset cooldown 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/test/java/com/couchbase/client/dcp/util/UserAgentBuilderTest.java: -------------------------------------------------------------------------------- 1 | package com.couchbase.client.dcp.util; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | import static org.junit.jupiter.api.Assertions.assertThrows; 7 | 8 | public class UserAgentBuilderTest { 9 | 10 | @Test 11 | void userAgent() throws Exception { 12 | String userAgent = new UserAgentBuilder() 13 | .append("Foo", null) 14 | .append("Bar", "1.0") 15 | .append("Zot", "2.0", "parens and backslashes should be escaped ()\\") 16 | .build(); 17 | 18 | assertEquals("Foo Bar/1.0 Zot/2.0 (parens and backslashes should be escaped \\(\\)\\\\)", userAgent); 19 | } 20 | 21 | @Test 22 | void commentsAreJoinedWithSemicolons() throws Exception { 23 | String userAgent = new UserAgentBuilder() 24 | .append("Foo", null, "a", "b", "c") 25 | .build(); 26 | 27 | assertEquals("Foo (a; b; c)", userAgent); 28 | } 29 | 30 | @Test 31 | void productNameMustNotBeNull() throws Exception { 32 | assertThrows(NullPointerException.class, () -> new UserAgentBuilder().append(null, null)); 33 | } 34 | 35 | @Test 36 | void productNameMustNotBeEmpty() throws Exception { 37 | assertThrows(IllegalArgumentException.class, () -> new UserAgentBuilder().append("", null)); 38 | } 39 | 40 | @Test 41 | void invalidCharsInTokensAreReplacedWithUnderscore() throws Exception { 42 | String userAgent = new UserAgentBuilder().append("Foo/(Bar\"", "1.0 beta 1").build(); 43 | assertEquals("Foo__Bar_/1.0_beta_1", userAgent); 44 | } 45 | 46 | @Test 47 | void nonAsciiCharactersAreReplaced() throws Exception { 48 | String userAgent = new UserAgentBuilder().append("Foö", "1.0-béta", "foô").build(); 49 | assertEquals("Fo_/1.0-b_ta (fo?)", userAgent); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/test/resources/com/couchbase/client/dcp/core/config/config-memcached-7.6.0.json: -------------------------------------------------------------------------------- 1 | {"rev":34060,"revEpoch":1,"name":"mc","nodeLocator":"ketama","bucketType":"memcached","uuid":"995747a3b1cc309a5cf421e1de927124","uri":"/pools/default/buckets/mc?bucket_uuid=995747a3b1cc309a5cf421e1de927124","streamingUri":"/pools/default/bucketsStreaming/mc?bucket_uuid=995747a3b1cc309a5cf421e1de927124","bucketCapabilitiesVer":"","bucketCapabilities":["cbhello","nodesExt"],"nodes":[{"hostname":"$HOST:8091","ports":{"direct":11210},"alternateAddresses":{"external":{"hostname":"booper","ports":{"mgmt":8091,"kv":21210}}}}],"nodesExt":[{"services":{"backupAPI":8097,"backupAPIHTTPS":18097,"backupGRPC":9124,"capi":8092,"capiSSL":18092,"cbas":8095,"cbasSSL":18095,"eventingAdminPort":8096,"eventingDebug":9140,"eventingSSL":18096,"fts":8094,"ftsGRPC":9130,"ftsGRPCSSL":19130,"ftsSSL":18094,"indexAdmin":9100,"indexHttp":9102,"indexHttps":19102,"indexScan":9101,"indexStreamCatchup":9104,"indexStreamInit":9103,"indexStreamMaint":9105,"kv":11210,"kvSSL":11207,"mgmt":8091,"mgmtSSL":18091,"n1ql":8093,"n1qlSSL":18093,"projector":9999},"thisNode":true,"alternateAddresses":{"external":{"hostname":"booper","ports":{"mgmt":8091,"kv":21210}}}}],"clusterCapabilitiesVer":[1,0],"clusterCapabilities":{"n1ql":["costBasedOptimizer","indexAdvisor","javaScriptFunctions","inlineFunctions","enhancedPreparedStatements","readFromReplica"],"search":["vectorSearch","scopedSearchIndex"]}} 2 | -------------------------------------------------------------------------------- /src/test/resources/com/couchbase/client/dcp/core/config/config_with_host_placeholder.json: -------------------------------------------------------------------------------- 1 | {"rev":61,"name":"travel-sample","uri":"/pools/default/buckets/travel-sample?bucket_uuid=94b9e193c801f081f71d965e9455e9c2","streamingUri":"/pools/default/bucketsStreaming/travel-sample?bucket_uuid=94b9e193c801f081f71d965e9455e9c2","nodes":[{"couchApiBase":"http://$HOST:8092/travel-sample%2B94b9e193c801f081f71d965e9455e9c2","hostname":"$HOST:8091","ports":{"direct":11210}}],"nodesExt":[{"services":{"mgmt":8091,"mgmtSSL":18091,"cbas":8095,"cbasSSL":18095,"eventingAdminPort":8096,"eventingDebug":9140,"eventingSSL":18096,"fts":8094,"ftsSSL":18094,"ftsGRPC":9130,"ftsGRPCSSL":19130,"indexAdmin":9100,"indexScan":9101,"indexHttp":9102,"indexStreamInit":9103,"indexStreamCatchup":9104,"indexStreamMaint":9105,"indexHttps":19102,"kv":11210,"kvSSL":11207,"capi":8092,"capiSSL":18092,"projector":9999,"projector":9999,"n1ql":8093,"n1qlSSL":18093},"thisNode":true}],"nodeLocator":"vbucket","uuid":"94b9e193c801f081f71d965e9455e9c2","ddocs":{"uri":"/pools/default/buckets/travel-sample/ddocs"},"vBucketServerMap":{"hashAlgorithm":"CRC","numReplicas":1,"serverList":["$HOST:11210"],"vBucketMap":[[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1]]},"bucketCapabilitiesVer":"","bucketCapabilities":["durableWrite","couchapi","dcp","cbhello","touch","cccp","xdcrCheckpointing","nodesExt","xattr"],"clusterCapabilitiesVer":[1,0],"clusterCapabilities":{"n1ql":["enhancedPreparedStatements"]}} 2 | -------------------------------------------------------------------------------- /src/test/resources/com/couchbase/client/dcp/core/config/config_with_invalid_capability.json: -------------------------------------------------------------------------------- 1 | {"rev":3463,"name":"default","uri":"/pools/default/buckets/default?bucket_uuid=28dd0957f66e6a44571f9e8f888cc47c","streamingUri":"/pools/default/bucketsStreaming/default?bucket_uuid=28dd0957f66e6a44571f9e8f888cc47c","nodes":[{"couchApiBase":"http://127.0.0.1:8092/default%2B28dd0957f66e6a44571f9e8f888cc47c","hostname":"127.0.0.1:8091","ports":{"proxy":11211,"direct":11210}}],"nodesExt":[{"services":{"mgmt":8091,"mgmtSSL":18091,"fts":8094,"ftsSSL":18094,"indexAdmin":9100,"indexScan":9101,"indexHttp":9102,"indexStreamInit":9103,"indexStreamCatchup":9104,"indexStreamMaint":9105,"indexHttps":19102,"capiSSL":18092,"capi":8092,"kvSSL":11207,"projector":9999,"kv":11210,"moxi":11211,"n1ql":8093,"n1qlSSL":18093},"thisNode":true}],"nodeLocator":"vbucket","uuid":"28dd0957f66e6a44571f9e8f888cc47c","ddocs":{"uri":"/pools/default/buckets/default/ddocs"},"vBucketServerMap":{"hashAlgorithm":"CRC","numReplicas":1,"serverList":["127.0.0.1:11210"],"vBucketMap":[[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1],[0,-1]]},"bucketCapabilitiesVer":"","bucketCapabilities":["xattr","dcp","cbhello","touch","peek-a-boo!","couchapi","cccp","xdcrCheckpointing","nodesExt"]} -------------------------------------------------------------------------------- /src/test/resources/com/couchbase/client/dcp/message/encoded-xattrs.txt: -------------------------------------------------------------------------------- 1 | +-------------------------------------------------+ 2 | | 0 1 2 3 4 5 6 7 8 9 a b c d e f | 3 | +--------+-------------------------------------------------+----------------+ 4 | |00000000| 00 00 00 72 00 00 00 21 5f 73 79 6e 63 00 7b 22 |...r...!_sync.{"| 5 | |00000010| 63 61 73 22 3a 22 64 65 61 64 62 65 65 66 63 61 |cas":"deadbeefca| 6 | |00000020| 66 65 66 65 65 64 22 7d 00 00 00 00 49 6d 65 74 |fefeed"}....Imet| 7 | |00000030| 61 00 7b 22 61 75 74 68 6f 72 22 3a 22 54 72 6f |a.{"author":"Tro| 8 | |00000040| 6e 64 20 4e 6f 72 62 79 65 22 2c 22 63 6f 6e 74 |nd Norbye","cont| 9 | |00000050| 65 6e 74 2d 74 79 70 65 22 3a 22 61 70 70 6c 69 |ent-type":"appli| 10 | |00000060| 63 61 74 69 6f 6e 2f 6f 63 74 65 74 2d 73 74 72 |cation/octet-str| 11 | |00000070| 65 61 6d 22 7d 00 |eam"}. | 12 | +--------+-------------------------------------------------+----------------+ 13 | -------------------------------------------------------------------------------- /src/test/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | --------------------------------------------------------------------------------