Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
165ca5d
Python V5 - creating wiring for backend dispatch
dibahlfi May 13, 2026
9e8de0d
create_item operation
dibahlfi May 13, 2026
192fb91
adding build support for PY03 bindings
dibahlfi May 15, 2026
5c64327
added parity checker for create item
dibahlfi May 16, 2026
ec5da3d
fixing bugs
dibahlfi May 17, 2026
179fe97
mapping headers for create_item
dibahlfi May 17, 2026
8c4635a
refactoring tests
dibahlfi May 20, 2026
229671f
adding missed class
dibahlfi May 23, 2026
d6e9072
fix - fixing parity checker
dibahlfi Jun 5, 2026
5ec25d8
fix - parity checker clean up
dibahlfi Jun 5, 2026
a299374
rust migration - adding delete_item initial impl
dibahlfi Jun 6, 2026
d72ad31
delete item cleaning up comments
dibahlfi Jun 7, 2026
d6c9403
adding read_item initial impl
dibahlfi Jun 9, 2026
8db4444
adding upsert_item initial impl
dibahlfi Jun 10, 2026
3480999
adding replace_item initial impl
dibahlfi Jun 10, 2026
f020d22
cleaning up comments
dibahlfi Jun 13, 2026
e10f8bb
cleaning up comments
dibahlfi Jun 15, 2026
eb946d6
Merge branch 'main' into users/dibahl/python-sdk-with-rust-driver
dibahlfi Jun 18, 2026
5f51a58
refactoring crud and cosmos client initialization
dibahlfi Jun 20, 2026
224e2fc
refactoring crud and cosmos client initialization
dibahlfi Jun 21, 2026
31f5913
refactoring crud and cosmos client initialization
dibahlfi Jun 22, 2026
31c1f8f
refactoring and cleaning up comments
dibahlfi Jun 22, 2026
cacd1b4
adding perf tests
dibahlfi Jun 25, 2026
2e8d47b
fixing perf tests
dibahlfi Jun 25, 2026
3d2dd55
fixing more perf configuration
dibahlfi Jun 26, 2026
1b78ed7
fixing more perf configuration
dibahlfi Jun 26, 2026
cf096cc
Fix NameError: import _loop_lag_monitor explicitly in workload.py
dibahlfi Jun 26, 2026
c170732
Treat SIGINT exit 130 as success in perf driver scripts
dibahlfi Jun 26, 2026
0abcc4e
fixing a security issue
dibahlfi Jun 27, 2026
a6ddf94
perf drill: add timeout --kill-after safety net to unattended driver …
dibahlfi Jun 27, 2026
f358588
perf drill: add post-run integrity gate (methodology flags #2/#3/#4)
dibahlfi Jun 27, 2026
9f4a59a
fixing timeout
dibahlfi Jun 27, 2026
f954d54
perf harness: graceful cooperative shutdown for the load loops
dibahlfi Jun 28, 2026
a171f46
fixing a blocking bug
dibahlfi Jun 28, 2026
d6ef061
adding test coverage
dibahlfi Jun 29, 2026
18f9706
adding missed file
dibahlfi Jun 29, 2026
bec846d
cleaning up comments
dibahlfi Jun 29, 2026
c0c1c6a
Perf drill: concrete backend provenance + harness hardening
dibahlfi Jun 30, 2026
81566af
refactoring perf scripts
dibahlfi Jun 30, 2026
0bcd7fe
adding more tests
dibahlfi Jun 30, 2026
89f09ff
adding diagnostics
dibahlfi Jul 1, 2026
2a848ad
cleaning up comments
dibahlfi Jul 2, 2026
e9c848d
Add Phase 0 baseline + Phase C scale-sweep results; harden provenance…
dibahlfi Jul 2, 2026
1c56bcf
Perf drill doc: add per-phase client VM names + engine build/versioni…
dibahlfi Jul 2, 2026
178dd04
Add per-attempt wire-diagnostics counters to the Rust binding
dibahlfi Jul 2, 2026
0d62335
perf harness: capture x-ms-request-duration-ms for client-vs-server l…
dibahlfi Jul 2, 2026
9e99c61
docs(perf): root-cause the Phase 0 Read/Create tail — no regression o…
dibahlfi Jul 2, 2026
b0463a1
Perf harness: driver provenance, run isolation, scale-out + create-se…
dibahlfi Jul 3, 2026
9cd5961
hardening perf scripts
dibahlfi Jul 3, 2026
16892eb
Cosmos perf harness: add mixed/doc-size/cold-start modes + provenance…
dibahlfi Jul 3, 2026
13b66bb
clean up
dibahlfi Jul 5, 2026
bce5a37
adding tests
dibahlfi Jul 7, 2026
681a587
adding documentation
dibahlfi Jul 7, 2026
f17959c
adding query_items and read_feed changes
dibahlfi Jul 9, 2026
9f8d625
adding feed_range_from_partition_key migration impl
dibahlfi Jul 10, 2026
77a4c34
adding read_all_items migration impl
dibahlfi Jul 13, 2026
b74adb8
adding read_offer migration impl
dibahlfi Jul 14, 2026
572cd6c
adding replace_offer migration impl
dibahlfi Jul 16, 2026
46f575f
adding feed_range_subset impl
dibahlfi Jul 17, 2026
94855f1
refactoring and adding tests
dibahlfi Jul 22, 2026
fe0db66
implementing create_database in rust
dibahlfi Jul 22, 2026
35a42b2
implementing create_database_if_not_exists in rust
dibahlfi Jul 23, 2026
690ff00
cleaning up comments
dibahlfi Jul 24, 2026
8af54ca
adding transport diagnostics string
dibahlfi Jul 24, 2026
94d71b8
fixing create_database_if_not_exists bug
dibahlfi Jul 24, 2026
df95dc2
adding release document
dibahlfi Jul 26, 2026
2e5a3e3
adding performance document
dibahlfi Jul 26, 2026
dc2104e
adding request flow document
dibahlfi Jul 26, 2026
edd98df
fixing release document
dibahlfi Jul 26, 2026
40ed219
adding queryplan support
dibahlfi Jul 28, 2026
c6fd038
adding comments for perf scripts
dibahlfi Jul 28, 2026
fd1e3f4
adding libs
dibahlfi Jul 28, 2026
5abb311
implementing database-read migration
dibahlfi Jul 31, 2026
78989ba
cleaning up scripts
dibahlfi Aug 1, 2026
4feeeef
adding list_databases rust impl
dibahlfi Aug 5, 2026
f9eaec2
adding database/throughput operations rust migration
dibahlfi Aug 9, 2026
c595948
refactoring and cleaning up
dibahlfi Aug 10, 2026
4348789
refactoring profiling scripts
dibahlfi Aug 11, 2026
590c80e
fixing profiling bugs
dibahlfi Aug 11, 2026
b0307dd
updating build_and_release documentation
dibahlfi Aug 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
120 changes: 120 additions & 0 deletions sdk/cosmos/azure-cosmos/azure/cosmos/_backend/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# -------------------------------------------------------------------------
"""Abstract backend type plus the two small data classes used to talk to it.

Every concrete backend (``CorePythonBackend``, ``RustBackend``)
implements the ``CosmosBackend`` ABC defined here. Container methods
call the backend through this ABC so that the dispatch site never has
to know which underlying transport actually ran the request.

``PreparedRequest`` is what the helper hands a backend; ``BackendResponse``
is what the helper expects back. Both are frozen dataclasses (immutable
after construction) so a backend cannot accidentally mutate the input it
was handed or the output it produced.
"""
from __future__ import annotations

import abc
from dataclasses import dataclass, field
from typing import Any, Mapping, Optional

from azure.core.utils import CaseInsensitiveDict


@dataclass(frozen=True)
class PreparedRequest:
"""A single Cosmos operation, fully prepared and ready to send.

The helper layer that owns request preparation builds one of these
from the user's ``create_item`` arguments. Both backends receive
the *same* instance so neither one re-derives the wire format from
the original kwargs; that is the only way to guarantee byte-for-byte
parity between them.
"""

#: e.g. ``"dbs/{db}/colls/{coll}"``.
container_link: str

#: The request body, already serialized to JSON bytes by the helper.
body_bytes: bytes

#: The partition-key header value, already serialized to its on-wire
#: JSON shape (e.g. ``'["customerA"]'`` for a single-value PK).
partition_key_header: str

#: Everything else that needs to ride on the request: triggers,
#: indexing directive, intended-collection-rid, etc.
headers: Mapping[str, str] = field(default_factory=dict)


@dataclass(frozen=True)
class BackendResponse:
"""Normalized shape every backend produces, regardless of transport.

The core-python backend builds one of these from an azure-core
``HttpResponse``; the Rust backend builds one from the PyO3 return
value. Code above the backend never branches on which backend
handled the call — it just reads these fields.
"""

#: HTTP status code returned by the service.
status_code: int

#: Cosmos sub-status code (header ``x-ms-substatus``); ``0`` if absent.
sub_status: int = 0

#: Full response header map. Populated from the underlying response
#: object so that long-tail headers (e.g. ``x-ms-cosmos-llsn``) survive
#: the trip across the backend boundary.
headers: Optional[CaseInsensitiveDict] = None

#: Raw response body bytes. May be empty for a 204 / no-content reply.
body: bytes = b""

#: Per-backend diagnostics blob the helper does not introspect. The
#: core-python backend stores its existing diagnostics here; the Rust
#: backend stores its structured diagnostics here.
diagnostics: Any = None


class CosmosBackend(abc.ABC):
"""Abstract dispatch target for any Cosmos operation (sync variant).

Every sync backend (``CorePythonBackend``, ``RustBackend``) inherits
from this class. The container's dispatch site holds one of these by
interface and calls ``create_item`` on it without knowing which
concrete backend it has.

Today, request preparation and response parsing still live in
their existing locations (``Container.create_item`` and the
``CosmosClientConnection`` helpers), so a backend that returns
``None`` from ``create_item`` is interpreted as "I have nothing to
return; the caller should run its existing in-place
implementation." Once the helper layer takes over request prep and
response parsing the contract tightens so that every backend
produces a real ``BackendResponse`` and the ``Optional`` annotations
go away.
"""

#: Short identifier used in two places: the startup INFO log line
#: emitted at client construction, and the per-request user-agent
#: suffix (``backend=<name>``). Concrete subclasses set this from
#: ``constants.BACKEND_NAME_CORE_PYTHON`` or
#: ``constants.BACKEND_NAME_RUST``.
name: str = "abstract"

@abc.abstractmethod
def create_item(self, prepared: Optional[PreparedRequest]) -> Optional[BackendResponse]:
"""Issue a single ``create_item`` call.

Returning ``None`` (the temporary contract until the helper
layer lands) tells the caller to use its existing in-place
implementation. Returning a ``BackendResponse`` tells the
caller to use that response directly. ``prepared`` may be
``None`` while the caller still owns request preparation.
"""
...

82 changes: 82 additions & 0 deletions sdk/cosmos/azure-cosmos/azure/cosmos/_backend/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# -------------------------------------------------------------------------
"""Constants for the backend dispatch layer.

Why this file exists:

The same strings — the two backend names, the env var, the per-request
kwarg key — show up in the factory, the two backend classes, the
user-agent policy, the container dispatch site, and the tests. If any
one of those copies drifts (for example, somebody types "corepython"
instead of "core-python"), the bug only shows up at runtime and is
annoying to track down.

Putting the strings in one place fixes that. Every other module that
needs one of these names imports it from here. Tests assert against
the same constants the production code uses, so renaming a value in
this file is a one-line change that the type checker and test suite
immediately tell you about.
"""
from __future__ import annotations

# ---------------------------------------------------------------------------
# Backend names
# ---------------------------------------------------------------------------
#
# The two values that the user can set on the constructor kwarg ``_backend``
# or in the ``COSMOS_BACKEND`` environment variable. They also show up in
# the per-request user-agent suffix (``backend=core-python`` or
# ``backend=rust``) so the server-side log knows which path handled a call.

#: The default backend. Routes through the existing in-tree azure-core
#: pipeline plus the ``CosmosClientConnection`` helpers. This is *not*
#: deprecated; it is the production path today and stays that way until
#: a future release decides the Rust path is ready to be the default.
BACKEND_NAME_CORE_PYTHON = "core-python"

#: The Rust-driver-backed path. Opt-in only today; the implementation
#: itself lands incrementally in later changes. Selecting this today
#: causes ``RustBackend.create_item`` to raise ``NotImplementedError``
#: so the developer gets a loud signal that they are running against a
#: stub.
BACKEND_NAME_RUST = "rust"

#: Tuple of every accepted backend name. The factory validates against
#: this; an unknown value raises ``ValueError`` at client construction.
VALID_BACKEND_NAMES = (BACKEND_NAME_CORE_PYTHON, BACKEND_NAME_RUST)

#: The backend the factory picks when the caller did not pass ``_backend=``
#: and the env var is unset. Stays ``core-python`` until a future release
#: explicitly flips it.
DEFAULT_BACKEND_NAME = BACKEND_NAME_CORE_PYTHON


# ---------------------------------------------------------------------------
# Selection knob
# ---------------------------------------------------------------------------

#: Environment variable read by the factory when no explicit ``_backend=``
#: was passed to the client constructor. Lets a developer or operator
#: switch backends without a code change. Precedence:
#: constructor kwarg > this env var > ``DEFAULT_BACKEND_NAME``.
BACKEND_ENV_VAR = "COSMOS_BACKEND"


# ---------------------------------------------------------------------------
# Per-request stamp
# ---------------------------------------------------------------------------

#: Key the container dispatch site writes into ``**kwargs`` (which become
#: the azure-core request-context options) recording which backend
#: actually handled a single call. ``CosmosUserAgentPolicy`` reads it from
#: there and appends ``backend=<name>`` to the User-Agent header.
#:
#: The value carried under this key is one of ``BACKEND_NAME_CORE_PYTHON``
#: or ``BACKEND_NAME_RUST``. It is stamped *after* the forced-fallback
#: decision so a request that fell back to core-python on a Rust-default
#: client correctly reports ``backend=core-python`` server-side.
REQUEST_OPTION_BACKEND_KEY = "cosmos_backend"

42 changes: 42 additions & 0 deletions sdk/cosmos/azure-cosmos/azure/cosmos/_backend/core_python.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# -------------------------------------------------------------------------
"""Sync core-python backend.

"Core-python" is the existing in-tree path: an azure-core pipeline plus
the ``CosmosClientConnection`` helpers that have shipped with this
package for years. It is the default and is *not* deprecated. It is also
the always-available fallback the dispatch site uses for any request
whose kwargs the Rust backend does not support yet (today: the two
kwargs ``availability_strategy`` and ``retry_write``).
"""
from __future__ import annotations

from typing import Optional

from .base import BackendResponse, CosmosBackend, PreparedRequest
from .constants import BACKEND_NAME_CORE_PYTHON


class CorePythonBackend(CosmosBackend):
"""Routes ``create_item`` calls through the existing azure-core stack.

Today this class's ``create_item`` returns ``None`` to tell the
dispatch site "delegate to the existing in-place call." When the
request-preparation helper and the response-parsing helper land,
this method will build an azure-core ``HttpRequest`` from the
``PreparedRequest``, send it through
``client_connection.pipeline_client``, and return a populated
``BackendResponse``.
"""

name = BACKEND_NAME_CORE_PYTHON

def create_item(self, prepared: Optional[PreparedRequest]) -> Optional[BackendResponse]:
# Returning None tells the container's dispatch site to fall
# through to the existing in-place create_item code path. The
# real adapter lands once the helper layer exists.
return None

74 changes: 74 additions & 0 deletions sdk/cosmos/azure-cosmos/azure/cosmos/_backend/factory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# -------------------------------------------------------------------------
"""Factory that picks which backend a single client will use.

A ``CosmosClient`` calls ``make_backend(...)`` exactly once at
construction time and stores the returned object. Every subsequent
``create_item`` call on every container created by that client dispatches
through the same instance.

Selection precedence (highest wins):

1. The value the caller passed to the client constructor as the
private kwarg ``_backend=``.
2. The value of the ``COSMOS_BACKEND`` environment variable.
3. The default, ``core-python``.

If a value comes in that is not ``"core-python"`` or ``"rust"``, the
factory raises ``ValueError`` immediately at client construction time.
Failing loud is intentional — a typo'd value silently falling back to
the default would mask configuration drift in production.
"""
from __future__ import annotations

import os
from typing import Optional

from .base import CosmosBackend
from .constants import (
BACKEND_ENV_VAR,
BACKEND_NAME_RUST,
DEFAULT_BACKEND_NAME,
VALID_BACKEND_NAMES,
)
from .core_python import CorePythonBackend
from .rust import RustBackend


def resolve_backend_name(explicit: Optional[str]) -> str:
"""Return one of the values in ``VALID_BACKEND_NAMES`` after applying
the precedence rules above.

Shared between the sync and async factories so the precedence rules,
valid values, and error message live in one place.
"""
if explicit is not None:
choice = explicit
else:
choice = os.environ.get(BACKEND_ENV_VAR, DEFAULT_BACKEND_NAME)
if choice not in VALID_BACKEND_NAMES:
raise ValueError(
"Invalid backend {!r}. Expected one of {}. "
"Set the constructor kwarg _backend=, or the {} environment variable.".format(
choice, VALID_BACKEND_NAMES, BACKEND_ENV_VAR
)
)
return choice


def make_backend(explicit: Optional[str]) -> CosmosBackend:
"""Build the single backend instance a sync ``CosmosClient`` will hold.

``explicit`` is what the caller passed as ``_backend=`` (or ``None`` if
they passed nothing — in which case the env var, then the default, are
consulted). The returned object is either a ``CorePythonBackend`` or a
``RustBackend``.
"""
name = resolve_backend_name(explicit)
if name == BACKEND_NAME_RUST:
return RustBackend()
return CorePythonBackend()

62 changes: 62 additions & 0 deletions sdk/cosmos/azure-cosmos/azure/cosmos/_backend/rust.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# -------------------------------------------------------------------------
"""Sync Rust backend.

This is the only Python module allowed to import the compiled PyO3
module ``azure.cosmos._azure_cosmos_pyo3``. The import-guard test
(``tests/test_backend_wiring_unit.py``) enforces that rule by walking
every ``.py`` file under ``azure/cosmos/`` and failing the build if any
other module reaches across the abstraction.

The compiled PyO3 module may not be present in every checkout (a fresh
clone will not have run ``maturin develop`` yet). The import below is
guarded with ``try / except ImportError`` so this file can still be
loaded; ``RustBackend.create_item`` will then raise
``NotImplementedError`` for any caller that asks for the Rust backend.
"""
from __future__ import annotations

import logging
from typing import Any, Optional

from .base import BackendResponse, CosmosBackend, PreparedRequest
from .constants import BACKEND_NAME_RUST

_LOGGER = logging.getLogger(__name__)

# Module-level reference set once at import time, under the GIL. Read-only
# afterwards, so it is safe to share across threads and across clients.
_pyo3_driver: Optional[Any] = None
try:
from azure.cosmos import _azure_cosmos_pyo3 # type: ignore[attr-defined]
_pyo3_driver = _azure_cosmos_pyo3
except ImportError:
_LOGGER.debug(
"_azure_cosmos_pyo3 module not available; RustBackend operations "
"will raise NotImplementedError until the PyO3 wrapper is built."
)


class RustBackend(CosmosBackend):
"""Routes ``create_item`` calls through the in-tree Rust driver.

Today this class's ``create_item`` raises ``NotImplementedError`` on
every call. That is the expected behavior for the dispatch-only
slice — a developer who runs the existing test suite with
``COSMOS_BACKEND=rust`` should see every create_item test fail
loudly, which proves the dispatch wiring works end-to-end. The real
implementation lands once the Rust-side gaps are closed and the
helper layer exists.
"""

name = BACKEND_NAME_RUST

def __init__(self) -> None:
self._driver = _pyo3_driver

def create_item(self, prepared: Optional[PreparedRequest]) -> Optional[BackendResponse]:
raise NotImplementedError("RustBackend.create_item not implemented yet")

Loading
Loading