Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 8cea247

Browse filesBrowse files
Gurov Ilyabradmiro
authored andcommitted
Add Firestore distributed counter snippets (GoogleCloudPlatform#2412)
* Add samples for distributed counters * Refactor list building * Excess instance * Empty line delete * Empty lines delete * Make comments more detailed. * Fix line too long * Move distributed counter samples and tests into separate files. * Blank lines fix. * Add firestore.Client * Test prefix. * Add fixture. * Line too long fix. * Line too long fix. * Update firestore/cloud-client/distributed_counters.py Co-Authored-By: Brad Miro <bmiro@google.com> * Update firestore/cloud-client/distributed_counters_test.py Co-Authored-By: Brad Miro <bmiro@google.com> * Update firestore/cloud-client/distributed_counters_test.py Co-Authored-By: Brad Miro <bmiro@google.com> * Update firestore/cloud-client/distributed_counters_test.py Co-Authored-By: Brad Miro <bmiro@google.com>
1 parent 27c5c18 commit 8cea247
Copy full SHA for 8cea247

File tree

Expand file treeCollapse file tree

2 files changed

+126
-0
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+126
-0
lines changed
+77Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Copyright 2019 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# [START fs_counter_classes]
16+
import random
17+
18+
from google.cloud import firestore
19+
20+
21+
class Shard(object):
22+
"""
23+
A shard is a distributed counter. Each shard can support being incremented
24+
once per second. Multiple shards are needed within a Counter to allow
25+
more frequent incrementing.
26+
"""
27+
28+
def __init__(self):
29+
self._count = 0
30+
31+
def to_dict(self):
32+
return {"count": self._count}
33+
34+
35+
class Counter(object):
36+
"""
37+
A counter stores a collection of shards which are
38+
summed to return a total count. This allows for more
39+
frequent incrementing than a single document.
40+
"""
41+
42+
def __init__(self, num_shards):
43+
self._num_shards = num_shards
44+
# [END fs_counter_classes]
45+
46+
# [START fs_create_counter]
47+
def init_counter(self, doc_ref):
48+
"""
49+
Create a given number of shards as
50+
subcollection of specified document.
51+
"""
52+
col_ref = doc_ref.collection("shards")
53+
54+
# Initialize each shard with count=0
55+
for num in range(self._num_shards):
56+
shard = Shard()
57+
col_ref.document(str(num)).set(shard.to_dict())
58+
# [END fs_create_counter]
59+
60+
# [START fs_increment_counter]
61+
def increment_counter(self, doc_ref):
62+
"""Increment a randomly picked shard."""
63+
doc_id = random.randint(0, self._num_shards - 1)
64+
65+
shard_ref = doc_ref.collection("shards").document(str(doc_id))
66+
return shard_ref.update({"count": firestore.Increment(1)})
67+
# [END fs_increment_counter]
68+
69+
# [START fs_get_count]
70+
def get_count(self, doc_ref):
71+
"""Return a total count across all shards."""
72+
total = 0
73+
shards = doc_ref.collection("shards").list_documents()
74+
for shard in shards:
75+
total += shard.get().to_dict().get("count", 0)
76+
return total
77+
# [END fs_get_count]
+49Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Copyright 2019 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from google.cloud import firestore
16+
import pytest
17+
18+
import distributed_counters
19+
20+
21+
shards_list = []
22+
doc_ref = None
23+
24+
25+
@pytest.fixture
26+
def fs_client():
27+
yield firestore.Client()
28+
29+
# clean up
30+
for shard in shards_list:
31+
shard.delete()
32+
33+
if doc_ref:
34+
doc_ref.delete()
35+
36+
37+
def test_distributed_counters(fs_client):
38+
col = fs_client.collection("dc_samples")
39+
doc_ref = col.document("distributed_counter")
40+
counter = distributed_counters.Counter(2)
41+
counter.init_counter(doc_ref)
42+
43+
shards = doc_ref.collection("shards").list_documents()
44+
shards_list = [shard for shard in shards]
45+
assert len(shards_list) == 2
46+
47+
counter.increment_counter(doc_ref)
48+
counter.increment_counter(doc_ref)
49+
assert counter.get_count(doc_ref) == 2

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.