def test_scenario_c_server_side_durability(self):
     # Use a helper wrapper to retry our operation in the face of durability failures
     # remove is idempotent iff the app guarantees that the doc's id won't be reused (e.g. if it's a UUID).  This seems
     # a reasonable restriction.
     for durability_type in Durability:
         self.coll.upsert("id","fred",durability=ServerDurability(Durability.NONE))
         self.retry_idempotent_remove_server_side(
             lambda: self.coll.remove("id", RemoveOptions(durability=ServerDurability(durability_type))))
Пример #2
0
    async def _mset(self,
                    key,
                    doc,
                    ttl=0,
                    persist_to=0,
                    replicate_to=0,
                    durability_level=Durability.NONE):

        try:
            if persist_to != 0 or replicate_to != 0:
                durability = ClientDurability(
                    replicate_to=Cardinal(replicate_to),
                    persist_to=Cardinal(persist_to))
            else:
                durability = ServerDurability(durability_level)
            if ttl != 0:
                timedelta = datetime.timedelta(ttl)
                upsert_options = UpsertOptions(expiry=timedelta,
                                               durability=durability)
            else:
                upsert_options = UpsertOptions(durability=durability)
            await self.cb.upsert(key, doc, options=upsert_options)
        except TemporaryFailException:
            logging.warn("temp failure during mset - cluster may be unstable")
        except TimeoutException:
            logging.warn(f"[{self.name}] cluster timed trying to handle mset")
        except NetworkException as nx:
            logging.error("network error")
            logging.error(nx)
        except Exception as ex:
            logging.error(ex)
 def test_server_durable_insert(self):
     if not self.supports_sync_durability():
         raise SkipTest("ServerDurability not supported")
     durability = ServerDurability(level=Durability.PERSIST_TO_MAJORITY)
     self.cb.insert(self.NOKEY, self.CONTENT,
                    InsertOptions(durability=durability))
     result = self.cb.get(self.NOKEY)
     self.assertEqual(self.CONTENT, result.content_as[dict])
def get_cluster():
    opts = ClusterOptions(
        authenticator=PasswordAuthenticator("Administrator", "password"),
        transaction_config=TransactionConfig(
            durability=ServerDurability(DurabilityLevel.PERSIST_TO_MAJORITY)))

    example_cluster = Cluster.connect('couchbase://localhost', opts)
    return example_cluster
 def test_server_durable_replace(self):
     content = {"new": "content"}
     if not self.supports_sync_durability():
         raise SkipTest("ServerDurability not supported")
     durability = ServerDurability(level=Durability.PERSIST_TO_MAJORITY)
     self.cb.replace(self.KEY, content,
                     ReplaceOptions(durability=durability))
     result = self.cb.get(self.KEY)
     self.assertEqual(content, result.content_as[dict])
Пример #6
0
 async def _mdelete(self, key, durability_level=Durability.NONE):
     try:
         await self.cb.remove(
             key,
             RemoveOptions(durability=ServerDurability(durability_level)))
     except DocumentNotFoundException as nf:
         logging.warn(f"[{self.name}] get key not found!  %s: " % nf.key)
     except TimeoutException:
         logging.warn(
             "cluster timed out trying to handle mdelete - cluster may be unstable"
         )
     except NetworkException as nx:
         logging.error("network error")
         logging.error(nx)
     except Exception as ex:
         logging.error(ex)
    def test_mutatein(self,  # type: Scenarios
                      dur_name):
        durability=Durability[dur_name]
        dur_option = DurabilityOptionBlock(durability=ServerDurability(level=durability))
        count = 0
        replica_count = self.bucket._bucket.configured_replica_count
        if dur_name != Durability.NONE and (replica_count == 0 or self.is_mock):
            raise SkipTest("cluster will not support {}".format(dur_name))
        if not self.supports_sync_durability():
            dur_option = self.sdk3_to_sdk2_durability(dur_name, replica_count)

        somecontents = {'some': {'path': 'keith'}}
        key="{}_{}".format("somekey_{}", count)
        try:
            self.coll.remove(key)
        except:
            pass
        self.coll.insert(key, somecontents)
        inserted_value = "inserted_{}".format(count)
        replacement_value = "replacement_{}".format(count)
        count += 1
        try:
            self.coll.mutate_in(key, (
                SD.replace('some.path', replacement_value),
                SD.insert('some.other.path', inserted_value, create_parents=True),
            ), dur_option)


            somecontents['some']['path'] = replacement_value
            somecontents['some'].update({'other': {'path': inserted_value}})
            self.assertEqual(somecontents, self.coll.get(key).content)
        except NotSupportedException as e:
            if not self.is_mock:
                raise
            else:
                logging.error("Assuming failure is due to mock not supporting durability")
        except couchbase.exceptions.TimeoutException as e:
            self.assertIn("Operational",e.message)
            raise SkipTest("Raised {}, skipped pending further verification".format(e.message))
 def test_server_durable_remove(self):
     if not self.supports_sync_durability():
         raise SkipTest("ServerDurability not supported")
     durability = ServerDurability(level=Durability.PERSIST_TO_MAJORITY)
     self.cb.remove(self.KEY, RemoveOptions(durability=durability))
     self.assertRaises(DocumentNotFoundException, self.cb.get, self.KEY)
Пример #9
0
    print("doc with key: {} already exists".format(key))
# end::DocumentExistsException[]

# tag::CASMismatchException[]
try:
    result = collection.get("hotel_10026")
    collection.replace("hotel_10026", {}, cas=result.cas)
except CASMismatchException:
    # the CAS value has changed
    pass
# end::CASMismatchException[]

# tag::DurabilitySyncWriteAmbiguousException[]
for i in range(5):
    try:
        durability = ServerDurability(level=Durability.PERSIST_TO_MAJORITY)
        collection.insert("my-key", {"title": "New Hotel"},
                          InsertOptions(durability=durability))
    except (
            DocumentExistsException,
            DurabilitySyncWriteAmbiguousException,
    ) as ex:
        # if previously retried and the document now exists,
        # we can assume it was written successfully by a previous ambiguous exception
        if isinstance(ex, DocumentExistsException) and i > 0:
            continue

        # simply retry the durable operation again
        if isinstance(ex, DurabilitySyncWriteAmbiguousException):
            continue
Пример #10
0
# tag::insert_w_opts[]
# Insert document with options
document = {"foo": "bar", "bar": "foo"}
opts = InsertOptions(timeout=timedelta(seconds=5))
result = collection.insert("document-key-opts",
                           document,
                           opts,
                           expiry=timedelta(seconds=30))
# end::insert_w_opts[]

try:
    # tag::durability[]
    # Upsert with Durability (Couchbase Server >= 6.5) level Majority
    document = dict(foo="bar", bar="foo")
    opts = UpsertOptions(durability=ServerDurability(Durability.MAJORITY))
    result = collection.upsert("document-key", document, opts)
    # end::durability[]
except CouchbaseException as ex:
    # we expect an exception on local/test host, as Durability requirement
    # requires appropriately configured cluster
    pass

try:
    # tag::obs_durability[]
    # Upsert with observe based durability (Couchbase Server < 6.5)
    document = {"foo": "bar", "bar": "foo"}
    opts = UpsertOptions(
        durability=ClientDurability(ReplicateTo.ONE, PersistTo.ONE))
    result = collection.upsert("document-key", document, opts)
    # end::obs_durability[]
Пример #11
0
    Couchbase Data Platform 6.5 refines these two options, with xref:synchronous-replication.adoc[Synchronous Replication] -- although they remain essentially the same in use -- as well as adding the option of xref:transactions.adoc[atomic document transactions].

The following example demonstrates using the newer durability features available in Couchbase server 6.5 onwards.

[source,python]
----
"""
# tag::upsert_syncrep[]
from couchbase.durability import Durability

document = dict(foo="bar", bar="foo")
result = collection.upsert("document-key",
                           document,
                           cas=12345,
                           expiry=timedelta(minutes=1),
                           durability=ServerDurability(Durability.MAJORITY))
# end::upsert_syncrep[]
"""
----

[TIP]
.Sub-Document Operations
====
All of these operations involve fetching the complete document from the Cluster.
Where the number of operations or other circumstances make bandwidth a significant issue, the SDK can work on just a specific _path_ of the document with xref:subdocument-operations.adoc[Sub-Docunent Operations].
====

== Retrieving full documents

Using the `Get()` method with the document key can be done in a similar fashion to the other operations:
    [source,python]
Пример #12
0
        MutateInOptions(cas=1234))
    # end::cas3[]
except (DocumentExistsException, CASMismatchException) as ex:
    # we expect an exception here as the CAS value is chosen
    # for example purposes
    print(ex)

try:
    # tag::obs_durability[]
    collection.mutate_in(
        "key", [SD.insert("username", "dreynholm")],
        MutateInOptions(durability=ClientDurability(
                        ReplicateTo.ONE,
                        PersistTo.ONE)))
    # end::obs_durability[]
except CouchbaseException as ex:
    print('Need to have more than 1 node for durability')
    print(ex)

try:
    # tag::durability[]
    collection.mutate_in(
        "customer123", [SD.insert("username", "dreynholm")],
        MutateInOptions(durability=ServerDurability(
                        Durability.MAJORITY)))
    # end::durability[]
except CouchbaseException as ex:
    print('Need to have more than 1 node for durability')
    print(ex)

def main():
    # tag::config[]
    opts = ClusterOptions(
        authenticator=PasswordAuthenticator("Administrator", "password"),
        transaction_config=TransactionConfig(
            durability=ServerDurability(DurabilityLevel.PERSIST_TO_MAJORITY)))

    cluster = Cluster.connect('couchbase://localhost', opts)
    # end::config[]

    test_doc = "foo"

    # tag::ts-bucket[]
    # get a reference to our bucket
    bucket = cluster.bucket("travel-sample")
    # end::ts-bucket[]

    # tag::ts-collection[]
    # get a reference to our collection
    collection = bucket.scope("inventory").collection("airline")
    # end::ts-collection[]

    # tag::ts-default-collection[]
    # get a reference to the default collection, required for older Couchbase server versions
    collection_default = bucket.default_collection()
    # tag::ts-default-collection[]

    # Set up for what we'll do below
    remove_or_warn(collection, 'doc-a')
    remove_or_warn(collection, 'doc-b')
    remove_or_warn(collection, 'doc-c')
    remove_or_warn(collection, test_doc)
    remove_or_warn(collection, 'docId')

    # await collection.upsert("doc-a", {})
    collection.upsert('doc-b', {})
    collection.upsert('doc-c', {})
    collection.upsert('doc-id', {})
    collection.upsert('a-doc', {})

    def txn_insert(ctx):
        ctx.insert(collection, test_doc, 'hello')

    try:
        cluster.transactions.run(txn_insert)
    except TransactionFailed as ex:
        print(f'Transaction did not reach commit point.  Error: {ex}')
    except TransactionCommitAmbiguous as ex:
        print(f'Transaction possibly committed.  Error: {ex}')

    # tag::create[]
    def txn_logic_ex(ctx  # type: AttemptContext
                     ):
        """
        … Your transaction logic here …
        """

    try:
        """
        'txn_logic_ex' is a Python closure that takes an AttemptContext. The
        AttemptContext permits getting, inserting, removing and replacing documents,
        performing N1QL queries, etc.

        Committing is implicit at the end of the closure.
        """
        cluster.transactions.run(txn_logic_ex)
    except TransactionFailed as ex:
        print(f'Transaction did not reach commit point.  Error: {ex}')
    except TransactionCommitAmbiguous as ex:
        print(f'Transaction possibly committed.  Error: {ex}')
    # end::create[]

    # tag::examples[]
    inventory = cluster.bucket("travel-sample").scope("inventory")

    def txn_example(ctx):
        # insert doc
        ctx.insert(collection, 'doc-a', {})

        # get a doc
        doc_a = ctx.get(collection, 'doc-a')

        # replace a doc
        doc_b = ctx.get(collection, 'doc-b')
        content = doc_b.content_as[dict]
        content['transactions'] = 'are awesome!'
        ctx.replace(doc_b, content)

        # remove a doc
        doc_c = ctx.get(collection, 'doc-c')
        ctx.remove(doc_c)

        # tag::scope-example[]
        # Added the above tag (scope-example) to ignore this section in the docs for now.
        # Once the below TODO is addressed we can remove the tag completely.
        # N1QL query
        # @TODO:  clean up txns query options, scope, pos args and named args won't work
        # query_str = 'SELECT * FROM hotel WHERE country = $1 LIMIT 2'
        # res = ctx.query(query_str,
        #         TransactionQueryOptions(scope=inventory,
        #                                 positional_args = ['United Kingdom']))
        # end::scope-example[]
        query_str = 'SELECT * FROM `travel-sample`.inventory.hotel WHERE country = "United Kingdom" LIMIT 2;'
        res = ctx.query(query_str)
        rows = [r for r in res.rows()]

        query_str = 'UPDATE `travel-sample`.inventory.route SET airlineid = "airline_137" WHERE airline = "AF"'
        res = ctx.query(query_str)
        rows = [r for r in res.rows()]

    try:
        cluster.transactions.run(txn_example)
    except TransactionFailed as ex:
        print(f'Transaction did not reach commit point.  Error: {ex}')
    except TransactionCommitAmbiguous as ex:
        print(f'Transaction possibly committed.  Error: {ex}')
    # end::examples[]

    # execute other examples
    try:
        print('transaction - get')
        get(cluster, collection, 'doc-a')
        # be sure to use a new key here...
        print('transaction - get w/ read own writes')
        get_read_own_writes(cluster, collection, 'doc-id2',
                            {'some': 'content'})
        print('transaction - replace')
        replace(cluster, collection, 'doc-id')
        print('transaction - remove')
        remove(cluster, collection, 'doc-id')
        print('transaction - insert')
        insert(cluster, collection, 'doc-id', {'some': 'content'})
        print("transaction - query_examples")
        query_examples(cluster)
    except TransactionFailed as ex:
        print(f'Txn did not reach commit point.  Error: {ex}')
    except TransactionCommitAmbiguous as ex:
        print(f'Txn possibly committed.  Error: {ex}')