Skip to content

Commit

Permalink
Drop 'Session' as a promoted, top-level entity in docs. (googleapis#3792
Browse files Browse the repository at this point in the history
)
  • Loading branch information
tseaver authored and landrito committed Aug 22, 2017
1 parent 55d8cba commit 3a34f30
Show file tree
Hide file tree
Showing 8 changed files with 314 additions and 417 deletions.
98 changes: 98 additions & 0 deletions docs/spanner/advanced-session-pool-topics.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
Advanced Session Pool Topics
============================

Custom Session Pool Implementations
-----------------------------------

You can supply your own pool implementation, which must satisfy the
contract laid out in
:class:`~google.cloud.spanner.pool.AbstractSessionPool`:

.. code-block:: python
from google.cloud.spanner.pool import AbstractSessionPool
class MyCustomPool(AbstractSessionPool):
def __init__(self, custom_param):
super(MyCustomPool, self).__init__()
self.custom_param = custom_param
def bind(self, database):
...
def get(self, read_only=False):
...
def put(self, session, discard_if_full=True):
...
pool = MyCustomPool(custom_param=42)
database = instance.database(DATABASE_NAME, pool=pool)
Lowering latency for read / query operations
--------------------------------------------

Some applications may need to minimize latency for read operations, including
particularly the overhead of making an API request to create or refresh a
session. :class:`~google.cloud.spanner.pool.PingingPool` is designed for such
applications, which need to configure a background thread to do the work of
keeping the sessions fresh.

Create an instance of :class:`~google.cloud.spanner.pool.PingingPool`:

.. code-block:: python
from google.cloud.spanner import Client
from google.cloud.spanner.pool import PingingPool
client = Client()
instance = client.instance(INSTANCE_NAME)
pool = PingingPool(size=10, default_timeout=5, ping_interval=300)
database = instance.database(DATABASE_NAME, pool=pool)
Set up a background thread to ping the pool's session, keeping them
from becoming stale:

.. code-block:: python
import threading
background = threading.Thread(target=pool.ping, name='ping-pool')
background.daemon = True
background.start()
Lowering latency for mixed read-write operations
------------------------------------------------

Some applications may need to minimize latency for read write operations,
including particularly the overhead of making an API request to create or
refresh a session or to begin a session's transaction.
:class:`~google.cloud.spanner.pool.TransactionPingingPool` is designed for
such applications, which need to configure a background thread to do the work
of keeping the sessions fresh and starting their transactions after use.

Create an instance of
:class:`~google.cloud.spanner.pool.TransactionPingingPool`:

.. code-block:: python
from google.cloud.spanner import Client
from google.cloud.spanner.pool import TransactionPingingPool
client = Client()
instance = client.instance(INSTANCE_NAME)
pool = TransactionPingingPool(size=10, default_timeout=5, ping_interval=300)
database = instance.database(DATABASE_NAME, pool=pool)
Set up a background thread to ping the pool's session, keeping them
from becoming stale, and ensuring that each session has a new transaction
started before it is used:

.. code-block:: python
import threading
background = threading.Thread(target=pool.ping, name='ping-pool')
background.daemon = True
background.start()
139 changes: 136 additions & 3 deletions docs/spanner/database-usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,141 @@ method:
:meth:`~google.cloud.spanner.instance.Operation.finished`
will result in an :exc`ValueError` being raised.

Non-Admin Database Usage
========================

Next Step
---------
Use a Snapshot to Read / Query the Database
-------------------------------------------

Next, learn about :doc:`session-crud-usage`.
A snapshot represents a read-only point-in-time view of the database.

Calling :meth:`~google.cloud.spanner.database.Database.snapshot` with
no arguments creates a snapshot with strong concurrency:

.. code:: python
with database.snapshot() as snapshot:
do_something_with(snapshot)
See :class:`~google.cloud.spanner.snapshot.Snapshot` for the other options
which can be passed.

.. note::

:meth:`~google.cloud.spanner.database.Database.snapshot` returns an
object intended to be used as a Python context manager (i.e., as the
target of a ``with`` statement). Use the instance, and any result
sets returned by its ``read`` or ``execute_sql`` methods, only inside
the block created by the ``with`` statement.

See :doc:`snapshot-usage` for more complete examples of snapshot usage.

Use a Batch to Modify Rows in the Database
------------------------------------------

A batch represents a bundled set of insert/upsert/update/delete operations
on the rows of tables in the database.

.. code:: python
with database.batch() as batch:
batch.insert_or_update(table, columns, rows)
batch.delete(table, keyset_to_delete)
.. note::

:meth:`~google.cloud.spanner.database.Database.batch` returns an
object intended to be used as a Python context manager (i.e., as the
target of a ``with`` statement). It applies any changes made inside
the block of its ``with`` statement when exiting the block, unless an
exception is raised within the block. Use the batch only inside
the block created by the ``with`` statement.

See :doc:`batch-usage` for more complete examples of batch usage.

Use a Transaction to Query / Modify Rows in the Database
--------------------------------------------------------

A transaction represents the union of a "strong" snapshot and a batch:
it allows ``read`` and ``execute_sql`` operations, and accumulates
insert/upsert/update/delete operations.

Because other applications may be performing concurrent updates which
would invalidate the reads / queries, the work done by a transaction needs
to be bundled as a retryable "unit of work" function, which takes the
transaction as a required argument:

.. code:: python
def unit_of_work(transaction):
result = transaction.execute_sql(QUERY)
for emp_id, hours, pay in _compute_pay(result):
transaction.insert_or_update(
table='monthly_hours',
columns=['employee_id', 'month', 'hours', 'pay'],
values=[emp_id, month_start, hours, pay])
database.run_in_transaction(unit_of_work)
.. note::

:meth:`~google.cloud.spanner.database.Database.run_in_transaction`
commits the transaction automatically if the "unit of work" function
returns without raising an exception.

.. note::

:meth:`~google.cloud.spanner.database.Database.run_in_transaction`
retries the "unit of work" function if the read / query operatoins
or the commit are aborted due to concurrent updates

See :doc:`transaction-usage` for more complete examples of transaction usage.

Configuring a session pool for a database
-----------------------------------------

Under the covers, the ``snapshot``, ``batch``, and ``run_in_transaction``
methods use a pool of :class:`~google.cloud.spanner.session.Session` objects
to manage their communication with the back-end. You can configure
one of the pools manually to control the number of sessions, timeouts, etc.,
and then passing it to the :class:`~google.cloud.spanner.database.Database`
constructor:

.. code-block:: python
from google.cloud.spanner import Client
from google.cloud.spanner import FixedSizePool
client = Client()
instance = client.instance(INSTANCE_NAME)
pool = FixedSizePool(size=10, default_timeout=5)
database = instanc.database(DATABASE_NAME, pool=pool)
Note that creating a database with a pool may presume that its database
already exists, as it may need to pre-create sessions (rather than creating
them on demand, as the default implementation does).

You can supply your own pool implementation, which must satisfy the
contract laid out in :class:`~google.cloud.spanner.pool.AbstractSessionPool`:

.. code-block:: python
from google.cloud.pool import AbstractSessionPool
class MyCustomPool(AbstractSessionPool):
def __init__(self, database, custom_param):
super(MyCustomPool, self).__init__(database)
self.custom_param = custom_param
def get(self, read_only=False):
...
def put(self, session, discard_if_full=True):
...
database = instance.database(DATABASE_NAME, pool=pool)
pool = MyCustomPool(database, custom_param=42)
See :doc:`advanced-session-pool-topics` for more advanced coverage of
session pools.
80 changes: 0 additions & 80 deletions docs/spanner/session-crud-usage.rst

This file was deleted.

54 changes: 0 additions & 54 deletions docs/spanner/session-implicit-txn-usage.rst

This file was deleted.

Loading

0 comments on commit 3a34f30

Please sign in to comment.