We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Heartbeat leaves tombstones

Heartbeat leaves tombstones


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `kinto/core/storage/__init__.py`
Content:
```
1 import random
2 from collections import namedtuple
3 from pyramid.settings import asbool
4 
5 from kinto.core.logs import logger
6 from . import generators
7 
8 
9 Filter = namedtuple('Filter', ['field', 'value', 'operator'])
10 """Filtering properties."""
11 
12 Sort = namedtuple('Sort', ['field', 'direction'])
13 """Sorting properties."""
14 
15 DEFAULT_ID_FIELD = 'id'
16 DEFAULT_MODIFIED_FIELD = 'last_modified'
17 DEFAULT_DELETED_FIELD = 'deleted'
18 
19 _HEARTBEAT_DELETE_RATE = 0.6
20 _HEARTBEAT_COLLECTION_ID = '__heartbeat__'
21 _HEART_PARENT_ID = _HEARTBEAT_COLLECTION_ID
22 _HEARTBEAT_RECORD = {'__heartbeat__': True}
23 
24 
25 class StorageBase(object):
26     """Storage abstraction used by resource views.
27 
28     It is meant to be instantiated at application startup.
29     Any operation may raise a `HTTPServiceUnavailable` error if an error
30     occurs with the underlying service.
31 
32     Configuration can be changed to choose which storage backend will
33     persist the objects.
34 
35     :raises: :exc:`~pyramid:pyramid.httpexceptions.HTTPServiceUnavailable`
36     """
37 
38     id_generator = generators.UUID4()
39     """Id generator used when no one is provided for create."""
40 
41     def initialize_schema(self, dry_run=False):
42         """Create every necessary objects (like tables or indices) in the
43         backend.
44 
45         This is executed when the ``kinto migrate`` command is run.
46 
47         :param bool dry_run: simulate instead of executing the operations.
48         """
49         raise NotImplementedError
50 
51     def flush(self, auth=None):
52         """Remove **every** object from this storage.
53         """
54         raise NotImplementedError
55 
56     def collection_timestamp(self, collection_id, parent_id, auth=None):
57         """Get the highest timestamp of every objects in this `collection_id` for
58         this `parent_id`.
59 
60         .. note::
61 
62             This should take deleted objects into account.
63 
64         :param str collection_id: the collection id.
65         :param str parent_id: the collection parent.
66 
67         :returns: the latest timestamp of the collection.
68         :rtype: int
69         """
70         raise NotImplementedError
71 
72     def create(self, collection_id, parent_id, record, id_generator=None,
73                id_field=DEFAULT_ID_FIELD,
74                modified_field=DEFAULT_MODIFIED_FIELD,
75                auth=None):
76         """Create the specified `object` in this `collection_id` for this `parent_id`.
77         Assign the id to the object, using the attribute
78         :attr:`kinto.core.resource.model.Model.id_field`.
79 
80         .. note::
81 
82             This will update the collection timestamp.
83 
84         :raises: :exc:`kinto.core.storage.exceptions.UnicityError`
85 
86         :param str collection_id: the collection id.
87         :param str parent_id: the collection parent.
88         :param dict record: the object to create.
89 
90         :returns: the newly created object.
91         :rtype: dict
92         """
93         raise NotImplementedError
94 
95     def get(self, collection_id, parent_id, object_id,
96             id_field=DEFAULT_ID_FIELD,
97             modified_field=DEFAULT_MODIFIED_FIELD,
98             auth=None):
99         """Retrieve the object with specified `object_id`, or raise error
100         if not found.
101 
102         :raises: :exc:`kinto.core.storage.exceptions.RecordNotFoundError`
103 
104         :param str collection_id: the collection id.
105         :param str parent_id: the collection parent.
106 
107         :param str object_id: unique identifier of the object
108 
109         :returns: the object object.
110         :rtype: dict
111         """
112         raise NotImplementedError
113 
114     def update(self, collection_id, parent_id, object_id, record,
115                id_field=DEFAULT_ID_FIELD,
116                modified_field=DEFAULT_MODIFIED_FIELD,
117                auth=None):
118         """Overwrite the `object` with the specified `object_id`.
119 
120         If the specified id is not found, the object is created with the
121         specified id.
122 
123         .. note::
124 
125             This will update the collection timestamp.
126 
127         :param str collection_id: the collection id.
128         :param str parent_id: the collection parent.
129         :param str object_id: unique identifier of the object
130         :param dict record: the object to update or create.
131 
132         :returns: the updated object.
133         :rtype: dict
134         """
135         raise NotImplementedError
136 
137     def delete(self, collection_id, parent_id, object_id,
138                id_field=DEFAULT_ID_FIELD, with_deleted=True,
139                modified_field=DEFAULT_MODIFIED_FIELD,
140                deleted_field=DEFAULT_DELETED_FIELD,
141                auth=None, last_modified=None):
142         """Delete the object with specified `object_id`, and raise error
143         if not found.
144 
145         Deleted objects must be removed from the database, but their ids and
146         timestamps of deletion must be tracked for synchronization purposes.
147         (See :meth:`kinto.core.storage.StorageBase.get_all`)
148 
149         .. note::
150 
151             This will update the collection timestamp.
152 
153         :raises: :exc:`kinto.core.storage.exceptions.RecordNotFoundError`
154 
155         :param str collection_id: the collection id.
156         :param str parent_id: the collection parent.
157 
158         :param str object_id: unique identifier of the object
159         :param bool with_deleted: track deleted record with a tombstone
160 
161         :returns: the deleted object, with minimal set of attributes.
162         :rtype: dict
163         """
164         raise NotImplementedError
165 
166     def delete_all(self, collection_id, parent_id, filters=None,
167                    id_field=DEFAULT_ID_FIELD, with_deleted=True,
168                    modified_field=DEFAULT_MODIFIED_FIELD,
169                    deleted_field=DEFAULT_DELETED_FIELD,
170                    auth=None):
171         """Delete all objects in this `collection_id` for this `parent_id`.
172 
173         :param str collection_id: the collection id.
174         :param str parent_id: the collection parent.
175 
176         :param filters: Optionnally filter the objects to delete.
177         :type filters: list of :class:`kinto.core.storage.Filter`
178         :param bool with_deleted: track deleted records with a tombstone
179 
180         :returns: the list of deleted objects, with minimal set of attributes.
181         :rtype: list
182         """
183         raise NotImplementedError
184 
185     def purge_deleted(self, collection_id, parent_id, before=None,
186                       id_field=DEFAULT_ID_FIELD,
187                       modified_field=DEFAULT_MODIFIED_FIELD,
188                       auth=None):
189         """Delete all deleted object tombstones in this `collection_id`
190         for this `parent_id`.
191 
192         :param str collection_id: the collection id.
193         :param str parent_id: the collection parent.
194 
195         :param int before: Optionnal timestamp to limit deletion (exclusive)
196 
197         :returns: The number of deleted objects.
198         :rtype: int
199 
200         """
201         raise NotImplementedError
202 
203     def get_all(self, collection_id, parent_id, filters=None, sorting=None,
204                 pagination_rules=None, limit=None, include_deleted=False,
205                 id_field=DEFAULT_ID_FIELD,
206                 modified_field=DEFAULT_MODIFIED_FIELD,
207                 deleted_field=DEFAULT_DELETED_FIELD,
208                 auth=None):
209         """Retrieve all objects in this `collection_id` for this `parent_id`.
210 
211         :param str collection_id: the collection id.
212         :param str parent_id: the collection parent.
213 
214         :param filters: Optionally filter the objects by their attribute.
215             Each filter in this list is a tuple of a field, a value and a
216             comparison (see `kinto.core.utils.COMPARISON`). All filters
217             are combined using *AND*.
218         :type filters: list of :class:`kinto.core.storage.Filter`
219 
220         :param sorting: Optionnally sort the objects by attribute.
221             Each sort instruction in this list refers to a field and a
222             direction (negative means descending). All sort instructions are
223             cumulative.
224         :type sorting: list of :class:`kinto.core.storage.Sort`
225 
226         :param pagination_rules: Optionnally paginate the list of objects.
227             This list of rules aims to reduce the set of objects to the current
228             page. A rule is a list of filters (see `filters` parameter),
229             and all rules are combined using *OR*.
230         :type pagination_rules: list of list of
231             :class:`kinto.core.storage.Filter`
232 
233         :param int limit: Optionnally limit the number of objects to be
234             retrieved.
235 
236         :param bool include_deleted: Optionnally include the deleted objects
237             that match the filters.
238 
239         :returns: the limited list of objects, and the total number of
240             matching objects in the collection (deleted ones excluded).
241         :rtype: tuple
242         """
243         raise NotImplementedError
244 
245 
246 def heartbeat(backend):
247     def ping(request):
248         """Test that storage is operationnal.
249 
250         :param request: current request object
251         :type request: :class:`~pyramid:pyramid.request.Request`
252         :returns: ``True`` is everything is ok, ``False`` otherwise.
253         :rtype: bool
254         """
255         try:
256             auth = request.headers.get('Authorization')
257             if asbool(request.registry.settings.get('readonly')):
258                 # Do not try to write in readonly mode.
259                 backend.get_all(_HEARTBEAT_COLLECTION_ID, _HEART_PARENT_ID,
260                                 auth=auth)
261             else:
262                 if random.SystemRandom().random() < _HEARTBEAT_DELETE_RATE:
263                     backend.delete_all(_HEARTBEAT_COLLECTION_ID,
264                                        _HEART_PARENT_ID, auth=auth)
265                 else:
266                     backend.create(_HEARTBEAT_COLLECTION_ID, _HEART_PARENT_ID,
267                                    _HEARTBEAT_RECORD, auth=auth)
268             return True
269         except:
270             logger.exception("Heartbeat Error")
271             return False
272 
273     return ping
274
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/kinto/core/storage/__init__.py b/kinto/core/storage/__init__.py
--- a/kinto/core/storage/__init__.py
+++ b/kinto/core/storage/__init__.py
@@ -261,7 +261,8 @@
             else:
                 if random.SystemRandom().random() < _HEARTBEAT_DELETE_RATE:
                     backend.delete_all(_HEARTBEAT_COLLECTION_ID,
-                                       _HEART_PARENT_ID, auth=auth)
+                                       _HEART_PARENT_ID, with_deleted=False,
+                                       auth=auth)
                 else:
                     backend.create(_HEARTBEAT_COLLECTION_ID, _HEART_PARENT_ID,
                                    _HEARTBEAT_RECORD, auth=auth)

{"golden_diff": "diff --git a/kinto/core/storage/__init__.py b/kinto/core/storage/__init__.py\n--- a/kinto/core/storage/__init__.py\n+++ b/kinto/core/storage/__init__.py\n@@ -261,7 +261,8 @@\n             else:\n                 if random.SystemRandom().random() < _HEARTBEAT_DELETE_RATE:\n                     backend.delete_all(_HEARTBEAT_COLLECTION_ID,\n-                                       _HEART_PARENT_ID, auth=auth)\n+                                       _HEART_PARENT_ID, with_deleted=False,\n+                                       auth=auth)\n                 else:\n                     backend.create(_HEARTBEAT_COLLECTION_ID, _HEART_PARENT_ID,\n                                    _HEARTBEAT_RECORD, auth=auth)\n", "issue": "Heartbeat leaves tombstones\n\nHeartbeat leaves tombstones\n\n", "before_files": [{"content": "import random\nfrom collections import namedtuple\nfrom pyramid.settings import asbool\n\nfrom kinto.core.logs import logger\nfrom . import generators\n\n\nFilter = namedtuple('Filter', ['field', 'value', 'operator'])\n\"\"\"Filtering properties.\"\"\"\n\nSort = namedtuple('Sort', ['field', 'direction'])\n\"\"\"Sorting properties.\"\"\"\n\nDEFAULT_ID_FIELD = 'id'\nDEFAULT_MODIFIED_FIELD = 'last_modified'\nDEFAULT_DELETED_FIELD = 'deleted'\n\n_HEARTBEAT_DELETE_RATE = 0.6\n_HEARTBEAT_COLLECTION_ID = '__heartbeat__'\n_HEART_PARENT_ID = _HEARTBEAT_COLLECTION_ID\n_HEARTBEAT_RECORD = {'__heartbeat__': True}\n\n\nclass StorageBase(object):\n    \"\"\"Storage abstraction used by resource views.\n\n    It is meant to be instantiated at application startup.\n    Any operation may raise a `HTTPServiceUnavailable` error if an error\n    occurs with the underlying service.\n\n    Configuration can be changed to choose which storage backend will\n    persist the objects.\n\n    :raises: :exc:`~pyramid:pyramid.httpexceptions.HTTPServiceUnavailable`\n    \"\"\"\n\n    id_generator = generators.UUID4()\n    \"\"\"Id generator used when no one is provided for create.\"\"\"\n\n    def initialize_schema(self, dry_run=False):\n        \"\"\"Create every necessary objects (like tables or indices) in the\n        backend.\n\n        This is executed when the ``kinto migrate`` command is run.\n\n        :param bool dry_run: simulate instead of executing the operations.\n        \"\"\"\n        raise NotImplementedError\n\n    def flush(self, auth=None):\n        \"\"\"Remove **every** object from this storage.\n        \"\"\"\n        raise NotImplementedError\n\n    def collection_timestamp(self, collection_id, parent_id, auth=None):\n        \"\"\"Get the highest timestamp of every objects in this `collection_id` for\n        this `parent_id`.\n\n        .. note::\n\n            This should take deleted objects into account.\n\n        :param str collection_id: the collection id.\n        :param str parent_id: the collection parent.\n\n        :returns: the latest timestamp of the collection.\n        :rtype: int\n        \"\"\"\n        raise NotImplementedError\n\n    def create(self, collection_id, parent_id, record, id_generator=None,\n               id_field=DEFAULT_ID_FIELD,\n               modified_field=DEFAULT_MODIFIED_FIELD,\n               auth=None):\n        \"\"\"Create the specified `object` in this `collection_id` for this `parent_id`.\n        Assign the id to the object, using the attribute\n        :attr:`kinto.core.resource.model.Model.id_field`.\n\n        .. note::\n\n            This will update the collection timestamp.\n\n        :raises: :exc:`kinto.core.storage.exceptions.UnicityError`\n\n        :param str collection_id: the collection id.\n        :param str parent_id: the collection parent.\n        :param dict record: the object to create.\n\n        :returns: the newly created object.\n        :rtype: dict\n        \"\"\"\n        raise NotImplementedError\n\n    def get(self, collection_id, parent_id, object_id,\n            id_field=DEFAULT_ID_FIELD,\n            modified_field=DEFAULT_MODIFIED_FIELD,\n            auth=None):\n        \"\"\"Retrieve the object with specified `object_id`, or raise error\n        if not found.\n\n        :raises: :exc:`kinto.core.storage.exceptions.RecordNotFoundError`\n\n        :param str collection_id: the collection id.\n        :param str parent_id: the collection parent.\n\n        :param str object_id: unique identifier of the object\n\n        :returns: the object object.\n        :rtype: dict\n        \"\"\"\n        raise NotImplementedError\n\n    def update(self, collection_id, parent_id, object_id, record,\n               id_field=DEFAULT_ID_FIELD,\n               modified_field=DEFAULT_MODIFIED_FIELD,\n               auth=None):\n        \"\"\"Overwrite the `object` with the specified `object_id`.\n\n        If the specified id is not found, the object is created with the\n        specified id.\n\n        .. note::\n\n            This will update the collection timestamp.\n\n        :param str collection_id: the collection id.\n        :param str parent_id: the collection parent.\n        :param str object_id: unique identifier of the object\n        :param dict record: the object to update or create.\n\n        :returns: the updated object.\n        :rtype: dict\n        \"\"\"\n        raise NotImplementedError\n\n    def delete(self, collection_id, parent_id, object_id,\n               id_field=DEFAULT_ID_FIELD, with_deleted=True,\n               modified_field=DEFAULT_MODIFIED_FIELD,\n               deleted_field=DEFAULT_DELETED_FIELD,\n               auth=None, last_modified=None):\n        \"\"\"Delete the object with specified `object_id`, and raise error\n        if not found.\n\n        Deleted objects must be removed from the database, but their ids and\n        timestamps of deletion must be tracked for synchronization purposes.\n        (See :meth:`kinto.core.storage.StorageBase.get_all`)\n\n        .. note::\n\n            This will update the collection timestamp.\n\n        :raises: :exc:`kinto.core.storage.exceptions.RecordNotFoundError`\n\n        :param str collection_id: the collection id.\n        :param str parent_id: the collection parent.\n\n        :param str object_id: unique identifier of the object\n        :param bool with_deleted: track deleted record with a tombstone\n\n        :returns: the deleted object, with minimal set of attributes.\n        :rtype: dict\n        \"\"\"\n        raise NotImplementedError\n\n    def delete_all(self, collection_id, parent_id, filters=None,\n                   id_field=DEFAULT_ID_FIELD, with_deleted=True,\n                   modified_field=DEFAULT_MODIFIED_FIELD,\n                   deleted_field=DEFAULT_DELETED_FIELD,\n                   auth=None):\n        \"\"\"Delete all objects in this `collection_id` for this `parent_id`.\n\n        :param str collection_id: the collection id.\n        :param str parent_id: the collection parent.\n\n        :param filters: Optionnally filter the objects to delete.\n        :type filters: list of :class:`kinto.core.storage.Filter`\n        :param bool with_deleted: track deleted records with a tombstone\n\n        :returns: the list of deleted objects, with minimal set of attributes.\n        :rtype: list\n        \"\"\"\n        raise NotImplementedError\n\n    def purge_deleted(self, collection_id, parent_id, before=None,\n                      id_field=DEFAULT_ID_FIELD,\n                      modified_field=DEFAULT_MODIFIED_FIELD,\n                      auth=None):\n        \"\"\"Delete all deleted object tombstones in this `collection_id`\n        for this `parent_id`.\n\n        :param str collection_id: the collection id.\n        :param str parent_id: the collection parent.\n\n        :param int before: Optionnal timestamp to limit deletion (exclusive)\n\n        :returns: The number of deleted objects.\n        :rtype: int\n\n        \"\"\"\n        raise NotImplementedError\n\n    def get_all(self, collection_id, parent_id, filters=None, sorting=None,\n                pagination_rules=None, limit=None, include_deleted=False,\n                id_field=DEFAULT_ID_FIELD,\n                modified_field=DEFAULT_MODIFIED_FIELD,\n                deleted_field=DEFAULT_DELETED_FIELD,\n                auth=None):\n        \"\"\"Retrieve all objects in this `collection_id` for this `parent_id`.\n\n        :param str collection_id: the collection id.\n        :param str parent_id: the collection parent.\n\n        :param filters: Optionally filter the objects by their attribute.\n            Each filter in this list is a tuple of a field, a value and a\n            comparison (see `kinto.core.utils.COMPARISON`). All filters\n            are combined using *AND*.\n        :type filters: list of :class:`kinto.core.storage.Filter`\n\n        :param sorting: Optionnally sort the objects by attribute.\n            Each sort instruction in this list refers to a field and a\n            direction (negative means descending). All sort instructions are\n            cumulative.\n        :type sorting: list of :class:`kinto.core.storage.Sort`\n\n        :param pagination_rules: Optionnally paginate the list of objects.\n            This list of rules aims to reduce the set of objects to the current\n            page. A rule is a list of filters (see `filters` parameter),\n            and all rules are combined using *OR*.\n        :type pagination_rules: list of list of\n            :class:`kinto.core.storage.Filter`\n\n        :param int limit: Optionnally limit the number of objects to be\n            retrieved.\n\n        :param bool include_deleted: Optionnally include the deleted objects\n            that match the filters.\n\n        :returns: the limited list of objects, and the total number of\n            matching objects in the collection (deleted ones excluded).\n        :rtype: tuple\n        \"\"\"\n        raise NotImplementedError\n\n\ndef heartbeat(backend):\n    def ping(request):\n        \"\"\"Test that storage is operationnal.\n\n        :param request: current request object\n        :type request: :class:`~pyramid:pyramid.request.Request`\n        :returns: ``True`` is everything is ok, ``False`` otherwise.\n        :rtype: bool\n        \"\"\"\n        try:\n            auth = request.headers.get('Authorization')\n            if asbool(request.registry.settings.get('readonly')):\n                # Do not try to write in readonly mode.\n                backend.get_all(_HEARTBEAT_COLLECTION_ID, _HEART_PARENT_ID,\n                                auth=auth)\n            else:\n                if random.SystemRandom().random() < _HEARTBEAT_DELETE_RATE:\n                    backend.delete_all(_HEARTBEAT_COLLECTION_ID,\n                                       _HEART_PARENT_ID, auth=auth)\n                else:\n                    backend.create(_HEARTBEAT_COLLECTION_ID, _HEART_PARENT_ID,\n                                   _HEARTBEAT_RECORD, auth=auth)\n            return True\n        except:\n            logger.exception(\"Heartbeat Error\")\n            return False\n\n    return ping\n", "path": "kinto/core/storage/__init__.py"}], "after_files": [{"content": "import random\nfrom collections import namedtuple\nfrom pyramid.settings import asbool\n\nfrom kinto.core.logs import logger\nfrom . import generators\n\n\nFilter = namedtuple('Filter', ['field', 'value', 'operator'])\n\"\"\"Filtering properties.\"\"\"\n\nSort = namedtuple('Sort', ['field', 'direction'])\n\"\"\"Sorting properties.\"\"\"\n\nDEFAULT_ID_FIELD = 'id'\nDEFAULT_MODIFIED_FIELD = 'last_modified'\nDEFAULT_DELETED_FIELD = 'deleted'\n\n_HEARTBEAT_DELETE_RATE = 0.6\n_HEARTBEAT_COLLECTION_ID = '__heartbeat__'\n_HEART_PARENT_ID = _HEARTBEAT_COLLECTION_ID\n_HEARTBEAT_RECORD = {'__heartbeat__': True}\n\n\nclass StorageBase(object):\n    \"\"\"Storage abstraction used by resource views.\n\n    It is meant to be instantiated at application startup.\n    Any operation may raise a `HTTPServiceUnavailable` error if an error\n    occurs with the underlying service.\n\n    Configuration can be changed to choose which storage backend will\n    persist the objects.\n\n    :raises: :exc:`~pyramid:pyramid.httpexceptions.HTTPServiceUnavailable`\n    \"\"\"\n\n    id_generator = generators.UUID4()\n    \"\"\"Id generator used when no one is provided for create.\"\"\"\n\n    def initialize_schema(self, dry_run=False):\n        \"\"\"Create every necessary objects (like tables or indices) in the\n        backend.\n\n        This is executed when the ``kinto migrate`` command is run.\n\n        :param bool dry_run: simulate instead of executing the operations.\n        \"\"\"\n        raise NotImplementedError\n\n    def flush(self, auth=None):\n        \"\"\"Remove **every** object from this storage.\n        \"\"\"\n        raise NotImplementedError\n\n    def collection_timestamp(self, collection_id, parent_id, auth=None):\n        \"\"\"Get the highest timestamp of every objects in this `collection_id` for\n        this `parent_id`.\n\n        .. note::\n\n            This should take deleted objects into account.\n\n        :param str collection_id: the collection id.\n        :param str parent_id: the collection parent.\n\n        :returns: the latest timestamp of the collection.\n        :rtype: int\n        \"\"\"\n        raise NotImplementedError\n\n    def create(self, collection_id, parent_id, record, id_generator=None,\n               id_field=DEFAULT_ID_FIELD,\n               modified_field=DEFAULT_MODIFIED_FIELD,\n               auth=None):\n        \"\"\"Create the specified `object` in this `collection_id` for this `parent_id`.\n        Assign the id to the object, using the attribute\n        :attr:`kinto.core.resource.model.Model.id_field`.\n\n        .. note::\n\n            This will update the collection timestamp.\n\n        :raises: :exc:`kinto.core.storage.exceptions.UnicityError`\n\n        :param str collection_id: the collection id.\n        :param str parent_id: the collection parent.\n        :param dict record: the object to create.\n\n        :returns: the newly created object.\n        :rtype: dict\n        \"\"\"\n        raise NotImplementedError\n\n    def get(self, collection_id, parent_id, object_id,\n            id_field=DEFAULT_ID_FIELD,\n            modified_field=DEFAULT_MODIFIED_FIELD,\n            auth=None):\n        \"\"\"Retrieve the object with specified `object_id`, or raise error\n        if not found.\n\n        :raises: :exc:`kinto.core.storage.exceptions.RecordNotFoundError`\n\n        :param str collection_id: the collection id.\n        :param str parent_id: the collection parent.\n\n        :param str object_id: unique identifier of the object\n\n        :returns: the object object.\n        :rtype: dict\n        \"\"\"\n        raise NotImplementedError\n\n    def update(self, collection_id, parent_id, object_id, record,\n               id_field=DEFAULT_ID_FIELD,\n               modified_field=DEFAULT_MODIFIED_FIELD,\n               auth=None):\n        \"\"\"Overwrite the `object` with the specified `object_id`.\n\n        If the specified id is not found, the object is created with the\n        specified id.\n\n        .. note::\n\n            This will update the collection timestamp.\n\n        :param str collection_id: the collection id.\n        :param str parent_id: the collection parent.\n        :param str object_id: unique identifier of the object\n        :param dict record: the object to update or create.\n\n        :returns: the updated object.\n        :rtype: dict\n        \"\"\"\n        raise NotImplementedError\n\n    def delete(self, collection_id, parent_id, object_id,\n               id_field=DEFAULT_ID_FIELD, with_deleted=True,\n               modified_field=DEFAULT_MODIFIED_FIELD,\n               deleted_field=DEFAULT_DELETED_FIELD,\n               auth=None, last_modified=None):\n        \"\"\"Delete the object with specified `object_id`, and raise error\n        if not found.\n\n        Deleted objects must be removed from the database, but their ids and\n        timestamps of deletion must be tracked for synchronization purposes.\n        (See :meth:`kinto.core.storage.StorageBase.get_all`)\n\n        .. note::\n\n            This will update the collection timestamp.\n\n        :raises: :exc:`kinto.core.storage.exceptions.RecordNotFoundError`\n\n        :param str collection_id: the collection id.\n        :param str parent_id: the collection parent.\n\n        :param str object_id: unique identifier of the object\n        :param bool with_deleted: track deleted record with a tombstone\n\n        :returns: the deleted object, with minimal set of attributes.\n        :rtype: dict\n        \"\"\"\n        raise NotImplementedError\n\n    def delete_all(self, collection_id, parent_id, filters=None,\n                   id_field=DEFAULT_ID_FIELD, with_deleted=True,\n                   modified_field=DEFAULT_MODIFIED_FIELD,\n                   deleted_field=DEFAULT_DELETED_FIELD,\n                   auth=None):\n        \"\"\"Delete all objects in this `collection_id` for this `parent_id`.\n\n        :param str collection_id: the collection id.\n        :param str parent_id: the collection parent.\n\n        :param filters: Optionnally filter the objects to delete.\n        :type filters: list of :class:`kinto.core.storage.Filter`\n        :param bool with_deleted: track deleted records with a tombstone\n\n        :returns: the list of deleted objects, with minimal set of attributes.\n        :rtype: list\n        \"\"\"\n        raise NotImplementedError\n\n    def purge_deleted(self, collection_id, parent_id, before=None,\n                      id_field=DEFAULT_ID_FIELD,\n                      modified_field=DEFAULT_MODIFIED_FIELD,\n                      auth=None):\n        \"\"\"Delete all deleted object tombstones in this `collection_id`\n        for this `parent_id`.\n\n        :param str collection_id: the collection id.\n        :param str parent_id: the collection parent.\n\n        :param int before: Optionnal timestamp to limit deletion (exclusive)\n\n        :returns: The number of deleted objects.\n        :rtype: int\n\n        \"\"\"\n        raise NotImplementedError\n\n    def get_all(self, collection_id, parent_id, filters=None, sorting=None,\n                pagination_rules=None, limit=None, include_deleted=False,\n                id_field=DEFAULT_ID_FIELD,\n                modified_field=DEFAULT_MODIFIED_FIELD,\n                deleted_field=DEFAULT_DELETED_FIELD,\n                auth=None):\n        \"\"\"Retrieve all objects in this `collection_id` for this `parent_id`.\n\n        :param str collection_id: the collection id.\n        :param str parent_id: the collection parent.\n\n        :param filters: Optionally filter the objects by their attribute.\n            Each filter in this list is a tuple of a field, a value and a\n            comparison (see `kinto.core.utils.COMPARISON`). All filters\n            are combined using *AND*.\n        :type filters: list of :class:`kinto.core.storage.Filter`\n\n        :param sorting: Optionnally sort the objects by attribute.\n            Each sort instruction in this list refers to a field and a\n            direction (negative means descending). All sort instructions are\n            cumulative.\n        :type sorting: list of :class:`kinto.core.storage.Sort`\n\n        :param pagination_rules: Optionnally paginate the list of objects.\n            This list of rules aims to reduce the set of objects to the current\n            page. A rule is a list of filters (see `filters` parameter),\n            and all rules are combined using *OR*.\n        :type pagination_rules: list of list of\n            :class:`kinto.core.storage.Filter`\n\n        :param int limit: Optionnally limit the number of objects to be\n            retrieved.\n\n        :param bool include_deleted: Optionnally include the deleted objects\n            that match the filters.\n\n        :returns: the limited list of objects, and the total number of\n            matching objects in the collection (deleted ones excluded).\n        :rtype: tuple\n        \"\"\"\n        raise NotImplementedError\n\n\ndef heartbeat(backend):\n    def ping(request):\n        \"\"\"Test that storage is operationnal.\n\n        :param request: current request object\n        :type request: :class:`~pyramid:pyramid.request.Request`\n        :returns: ``True`` is everything is ok, ``False`` otherwise.\n        :rtype: bool\n        \"\"\"\n        try:\n            auth = request.headers.get('Authorization')\n            if asbool(request.registry.settings.get('readonly')):\n                # Do not try to write in readonly mode.\n                backend.get_all(_HEARTBEAT_COLLECTION_ID, _HEART_PARENT_ID,\n                                auth=auth)\n            else:\n                if random.SystemRandom().random() < _HEARTBEAT_DELETE_RATE:\n                    backend.delete_all(_HEARTBEAT_COLLECTION_ID,\n                                       _HEART_PARENT_ID, with_deleted=False,\n                                       auth=auth)\n                else:\n                    backend.create(_HEARTBEAT_COLLECTION_ID, _HEART_PARENT_ID,\n                                   _HEARTBEAT_RECORD, auth=auth)\n            return True\n        except:\n            logger.exception(\"Heartbeat Error\")\n            return False\n\n    return ping\n", "path": "kinto/core/storage/__init__.py"}]}