Skip to content
Permalink
Browse files
feat: add support for Point In Time Recovery (PITR) (#148)
* feat: add PITR-lite support

* fix: remove unneeded conversion for earliest_version_time

* test: fix list_databases list comprehension

* feat: add support for PITR-lite backups (#1)

* Backup changes

* Basic tests

* Add system tests

* Fix system tests

* Add retention period to backup systests

* style: fix lint errors

* test: fix failing backup system tests (#2)

* Remove unnecessary retention period setting

* Fix systests

* Review changes (#3)

* Remove unnecessary retention period setting

* Fix systests

* Review changes

* style: fix lint

Co-authored-by: larkee <larkee@users.noreply.github.com>
Co-authored-by: Zoe <zoc@google.com>
  • Loading branch information
3 people committed Feb 22, 2021
1 parent 36b12a7 commit a082e5d7d2195ab9429a8e0bef4a664b59fdf771
Showing with 318 additions and 11 deletions.
  1. +26 −2 google/cloud/spanner_v1/backup.py
  2. +23 −0 google/cloud/spanner_v1/database.py
  3. +19 −3 google/cloud/spanner_v1/instance.py
  4. +214 −3 tests/system/test_system.py
  5. +18 −3 tests/unit/test_backup.py
  6. +18 −0 tests/unit/test_database.py
@@ -51,14 +51,23 @@ class Backup(object):
:param expire_time: (Optional) The expire time that will be used to
create the backup. Required if the create method
needs to be called.
:type version_time: :class:`datetime.datetime`
:param version_time: (Optional) The version time that was specified for
the externally consistent copy of the database. If
not present, it is the same as the `create_time` of
the backup.
"""

def __init__(self, backup_id, instance, database="", expire_time=None):
def __init__(
self, backup_id, instance, database="", expire_time=None, version_time=None
):
self.backup_id = backup_id
self._instance = instance
self._database = database
self._expire_time = expire_time
self._create_time = None
self._version_time = version_time
self._size_bytes = None
self._state = None
self._referencing_databases = None
@@ -109,6 +118,16 @@ def create_time(self):
"""
return self._create_time

@property
def version_time(self):
"""Version time of this backup.
:rtype: :class:`datetime.datetime`
:returns: a datetime object representing the version time of
this backup
"""
return self._version_time

@property
def size_bytes(self):
"""Size of this backup in bytes.
@@ -190,7 +209,11 @@ def create(self):
raise ValueError("database not set")
api = self._instance._client.database_admin_api
metadata = _metadata_with_prefix(self.name)
backup = BackupPB(database=self._database, expire_time=self.expire_time,)
backup = BackupPB(
database=self._database,
expire_time=self.expire_time,
version_time=self.version_time,
)

future = api.create_backup(
parent=self._instance.name,
@@ -228,6 +251,7 @@ def reload(self):
self._database = pb.database
self._expire_time = pb.expire_time
self._create_time = pb.create_time
self._version_time = pb.version_time
self._size_bytes = pb.size_bytes
self._state = BackupPB.State(pb.state)
self._referencing_databases = pb.referencing_databases
@@ -107,6 +107,8 @@ def __init__(self, database_id, instance, ddl_statements=(), pool=None):
self._state = None
self._create_time = None
self._restore_info = None
self._version_retention_period = None
self._earliest_version_time = None

if pool is None:
pool = BurstyPool()
@@ -204,6 +206,25 @@ def restore_info(self):
"""
return self._restore_info

@property
def version_retention_period(self):
"""The period in which Cloud Spanner retains all versions of data
for the database.
:rtype: str
:returns: a string representing the duration of the version retention period
"""
return self._version_retention_period

@property
def earliest_version_time(self):
"""The earliest time at which older versions of the data can be read.
:rtype: :class:`datetime.datetime`
:returns: a datetime object representing the earliest version time
"""
return self._earliest_version_time

@property
def ddl_statements(self):
"""DDL Statements used to define database schema.
@@ -313,6 +334,8 @@ def reload(self):
self._state = DatabasePB.State(response.state)
self._create_time = response.create_time
self._restore_info = response.restore_info
self._version_retention_period = response.version_retention_period
self._earliest_version_time = response.earliest_version_time

def update_ddl(self, ddl_statements, operation_id=""):
"""Update DDL for this database.
@@ -400,7 +400,7 @@ def list_databases(self, page_size=None):
)
return page_iter

def backup(self, backup_id, database="", expire_time=None):
def backup(self, backup_id, database="", expire_time=None, version_time=None):
"""Factory to create a backup within this instance.
:type backup_id: str
@@ -415,13 +415,29 @@ def backup(self, backup_id, database="", expire_time=None):
:param expire_time:
Optional. The expire time that will be used when creating the backup.
Required if the create method needs to be called.
:type version_time: :class:`datetime.datetime`
:param version_time:
Optional. The version time that will be used to create the externally
consistent copy of the database. If not present, it is the same as
the `create_time` of the backup.
"""
try:
return Backup(
backup_id, self, database=database.name, expire_time=expire_time
backup_id,
self,
database=database.name,
expire_time=expire_time,
version_time=version_time,
)
except AttributeError:
return Backup(backup_id, self, database=database, expire_time=expire_time)
return Backup(
backup_id,
self,
database=database,
expire_time=expire_time,
version_time=version_time,
)

def list_backups(self, filter_="", page_size=None):
"""List backups for the instance.

0 comments on commit a082e5d

Please sign in to comment.