Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

gdp / doc / developer / tutorial / gdp-tutorial-part2.md @ master

History | View | Annotate | Download (10.5 KB)

1 8949c8d7 Nitesh Mor
% Writing GDP applications
2
3
# A typical application
4
5
The log interface acts as a proxy to interact with sensors and actuators. We
6
describe how one would go about designing a simple application. Imagine an
7
office building with some temperature sensors and some motor controlled window
8
blinds. We would like to design an application that looks at the current
9
temperature and some weather prediction feeds from the cloud to make a smart
10
decision about the window blinds. 
11
12
![An example GDP application](GDP_application_example.png)
13
14
As shown above, in order to do so, the application subscribes to all the
15
relevant logs and writes the actuation values to the actuator log. A gateway
16
working on behalf of the actuator subscribes to this actuation log and controls
17
the motors for the window blinds. Note that instead of two separate logs, a
18
composite log can be created for `Sensor 1` and `Sensor 2` in the diagram
19
above, provided that the gateway implements the single-writer semantics.
20
21
---
22
23
# Software Installation and Configuration
24
25
In this section, we talk about how to get access, install and use the GDP
26
client side library. As mentioned earlier, we have a C library for clients with
27
wrappers in other languages around this C-library.
28
29 eebee62a Nitesh Mor
The main GDP repository can be accessed in read-only mode by using
30 8949c8d7 Nitesh Mor
31 eebee62a Nitesh Mor
```
32
git clone https://repo.eecs.berkeley.edu/git-anon/projects/swarmlab/gdp.git
33
```
34
35
Or, in read-write mode either using HTTPS (requires username, password), or
36
using SSH (requires key setup):
37 8949c8d7 Nitesh Mor
38
```
39
git clone https://repo.eecs.berkeley.edu/git/projects/swarmlab/gdp.git
40
git clone repoman@repo.eecs.berkeley.edu:projects/swarmlab/gdp.git
41
```
42
43 eebee62a Nitesh Mor
The main GDP repository contains the core GDP library (`libgdp`), client-side
44
applications and language bindings, and the log-server (`gdplogd`). GDP-router
45
is maintained in a separate repository (`gdp_router_click.git`).  However, you
46
should not need to worry about it if you are just playing around with GDP.
47 2d3b765a Eric Allman
48 eebee62a Nitesh Mor
The repository `gdp-if.git` contains various interfaces to the GDP.  It is
49 2d3b765a Eric Allman
not really part of the GDP itself, but it may prove instructive.
50 8949c8d7 Nitesh Mor
51
52
## Compilation
53 eebee62a Nitesh Mor
54
In summary, assuming you have the required dependencies installed, `make
55 ee62a420 Eric Allman
install-dev-c` should install the C include files, C libraries, and basic
56 390904c6 Eric Allman
utility applications into system path. `make install-python` should
57
install the Python bindings in the system path as well. These `make`
58
targets do not create any necessary configuration files, however (see
59
below). For more details, refer to README.md in the main git tree.
60 8949c8d7 Nitesh Mor
61
## Infrastructure information
62 390904c6 Eric Allman
63 eebee62a Nitesh Mor
Refer to README.md in the main git tree.
64 8949c8d7 Nitesh Mor
65
*Note that the software/infrastructure is still in very early experimental
66
phase. We do not make any guarantees on data retention/backups at this moment.
67
As the code stabilizes, we will make better effort to maintain data. In the
68
meantime, contact us if you would like to use GDP for anything serious.*
69
70
## Configuration
71
72 eebee62a Nitesh Mor
The GDP library, log-server, and various other utility programs consult a
73
configuration file for the correct parameters to use.  At the very minimum, your
74
configuration file should contain the GDP router that your client should connect
75
to (unless someone else is running a local router in the same subnet as you are
76
in, in which case zeroconf should work). Refer to README.md in the main git
77
tree.
78 8949c8d7 Nitesh Mor
79
## Creating logs
80
81 1a02be05 Nitesh Mor
The main mechanism to create a log is using `gdp-create` (should be in your
82 eebee62a Nitesh Mor
system path after `make install-*`). For example,
83 8949c8d7 Nitesh Mor
84
```
85 1a02be05 Nitesh Mor
gdp-create -k none org.example.project.log17a
86 8949c8d7 Nitesh Mor
```
87
88 f0f1f0cf Nitesh Mor
will create a log named `org.example.project.log17a` on one of the default
89 eebee62a Nitesh Mor
log-servers at Berkeley.
90
91
Although you can create logs with any name, please stick to this convention
92
(with "project" being the project name or the user name, as appropriate) so we
93 1a02be05 Nitesh Mor
can avoid name collisions. `-k none` means that `gdp-create` will not attempt to
94 eebee62a Nitesh Mor
create a new signature key for signing appended data.  Although crucial to the
95
operation, key-management is better deferred to a stage when you are familiar
96 1a02be05 Nitesh Mor
with the basic operations of the GDP.  Also, note that `gdp-create` has several
97 eebee62a Nitesh Mor
other command-line options that will be useful later on.
98
99
Note that if you don't explicitly specify log-placement, a log-server at
100
Berkeley is picked at random for hosting your log. This is especially important
101
if you are running your own log-servers and want control over where data goes.
102 8949c8d7 Nitesh Mor
103
---
104
105
# Writing applications in Python
106
107
Even though the GDP library is written in C, we provide a python package `gdp`
108
that acts as a wrapper around the C-library. This python package enables quick
109
prototyping using an object-oriented interface to GDP. What follows is a quick
110
how-to on writing simple GDP programs in Python. Note that this document is
111
just a starting point and is not intended to be a comprehensive guide to the
112
complete interface. For a more thorough API documentation, refer to
113
`/lang/python/README`.
114
115 b0f1da2a Nitesh Mor
## Python package installation
116
117
The package `gdp` should be installed in your system path for python packages.
118
Once you have the required dependencies for compilation installed, something
119
like `make install-python` from the root of repository should do the trick (note
120 eebee62a Nitesh Mor
that running with `sudo` may be required). Note that this also installs the
121 1a02be05 Nitesh Mor
client side C libraries and various utilities (such as `gdp-create`) in system
122 eebee62a Nitesh Mor
path.
123 b0f1da2a Nitesh Mor
124 8949c8d7 Nitesh Mor
## Appending data
125
126
Let's start with a simple `Hello world` program, that writes some data to a
127 214b1337 Nitesh Mor
log and reads it back. Before we begin, we need to create the log; see *Creating
128
logs* above. The tutorial uses the logname `edu.berkeley.eecs.mor.01`, but
129
please replace it with the name of the log you create.
130 8949c8d7 Nitesh Mor
131 b0f1da2a Nitesh Mor
We need to import the package `gdp` to begin with.
132
 
133 8949c8d7 Nitesh Mor
```python
134
>>> import gdp
135
```
136
137
Once imported, we need to initialize the GDP package by calling `gdp_init()`.
138
An optional argument to `gdp_init()` is the address of a GDP-router. If no
139
address provided, a default value of the parameter `swarm.gdp.routers` is used
140 eebee62a Nitesh Mor
as configured by EP library. (See README.md for details).
141 8949c8d7 Nitesh Mor
142
```python
143 09a91891 Nitesh Mor
>>> # the following picks a router based on EP library configuration
144 8949c8d7 Nitesh Mor
>>> gdp.gdp_init()
145 09a91891 Nitesh Mor
>>> # For a specific router, use the following:
146
>>> # gdp.gdp_init('gdp-01.eecs.berkeley.edu:8007')
147 8949c8d7 Nitesh Mor
```
148
149
As mentioned earlier, we support human readable names for logs. The mechanism
150
for translating a human readable name to a 256-bit name is probably going to
151
change in the future, however, it is our hope that it should be a simple
152
change. The Python wrapper uses instances of class `gdp.GDP_NAME` for a name,
153
which could be initialized using a human readable name.
154
155
```python
156
>>> # Create a GDP_NAME object from a human readable python string
157 1a02be05 Nitesh Mor
>>> gin_name = gdp.GDP_NAME("edu.berkeley.eecs.mor.01")
158 8949c8d7 Nitesh Mor
```
159
160
Once we have a `GDP_NAME`, we can use this to open a handle to a log/GCL. A log
161
handle works like a file handle in some ways. We need to tell whether we want
162
to open the GCL in read-only mode (`gdp.GDP_MODE_RO`), or append-only mode
163
(`gdp.GDP_MODE_AO`), or read-and-append mode (`gdp.GDP_MODE_RA`).
164
165
```python
166
>>> # assume that this log already exists.
167 1a02be05 Nitesh Mor
>>> gin_handle = gdp.GDP_GIN(gin_name, gdp.GDP_MODE_RA)
168 8949c8d7 Nitesh Mor
```
169
170
Next, let's append a few records to the log. The unit of read/write to a log is
171 eebee62a Nitesh Mor
called a record--data with some automatically generated metadata--represented
172 1a02be05 Nitesh Mor
by a `GDP_DATUM` object. The `GDP_DATUM` object contains a `GDP_BUF` that holds
173
the actual data. (Please see the C-api for more details on the behavior of
174
buffer objects, and such).
175
176 8949c8d7 Nitesh Mor
177
```python
178 1a02be05 Nitesh Mor
>>> d = gdp.GDP_DATUM()
179 8949c8d7 Nitesh Mor
>>> for idx in xrange(10):
180 1a02be05 Nitesh Mor
...   d["buf"].reset()
181
...   d["buf"].write("Hello world " + str(idx)}
182
...   gin_handle.append(d)
183 8949c8d7 Nitesh Mor
```
184
185
That's it. Ideally, it should finish without throwing any errors, resulting in
186
10 records append to the log specified. 
187
188
Look at `/lang/python/apps/writer_test.py` for a full example.
189
190
## Reading data by record number
191
192
Next, let's read some data back and see if it matches what we wrote. Note that
193
we need to tell what record number we want to read, and record numbers start
194 1a02be05 Nitesh Mor
from 1. To read data, we just use `read_by_recno` method of the GDP_GIN instance
195
with the record number.
196 8949c8d7 Nitesh Mor
197
```python
198
>>> for idx in xrange(1,11):
199 1a02be05 Nitesh Mor
...   datum = gin_handle.read_by_recno(idx)
200
...   print datum["recno"], datum["buf"].peek()
201
(1, 'Hello world 0')
202
(2, 'Hello world 1')
203
(3, 'Hello world 2')
204
(4, 'Hello world 3')
205
(5, 'Hello world 4')
206
(6, 'Hello world 5')
207
(7, 'Hello world 6')
208
(8, 'Hello world 7')
209
(9, 'Hello world 8')
210
(10, 'Hello world 9')
211 8949c8d7 Nitesh Mor
```
212
213
So far, we saw how to read and write data by record number. However, most of
214
the times, we are interested in the most recent record. For this, we support
215
negative record numbers, i.e. `-1` refers to the most recent record, `-2`
216
refers to the second most recent record, and so on.
217
218
Look at `/lang/python/apps/reader_test.py` for a full example.
219
220
## Subscriptions
221
222
Next, let's see how can we subscribe to a log to get new data from a log as it
223 1a02be05 Nitesh Mor
gets appended. For this, we use `subscribe_by_recno` method of the `gdp.GDP_GIN`
224 8949c8d7 Nitesh Mor
instance.
225
226
```python
227
>>> # ignore the parameters for the moment
228 1a02be05 Nitesh Mor
>>> gin_handle.subscribe_by_recno(0, 0, None)
229 8949c8d7 Nitesh Mor
```
230
231
This subscription returns events, that we need to process in order to get
232
notified of the data as it appears.
233
234
```python
235
>>> while True:
236
...   # this blocks until there is a new event
237 1a02be05 Nitesh Mor
...   event = gin_handle.get_next_event(None)
238
...   # Events can be used to get the associated datum
239 8949c8d7 Nitesh Mor
...   if event["type"] == gdp.GDP_EVENT_DATA:
240
...     datum = event["datum"]
241 1a02be05 Nitesh Mor
...     print datum["buf"].peek()
242 8949c8d7 Nitesh Mor
...   else: 
243
...     # we ignore other event types for simplicity
244
...     break
245
```
246
247 1a02be05 Nitesh Mor
In the above code, `event` is an object of type `GDP_EVENT`, which can be used
248
to get the associated `GDP_DATUM` (and then `GDP_BUF`). In order to see the
249
above code in action, open another python console (while this is running), and
250
append some new data to the log just the way you saw above.
251 8949c8d7 Nitesh Mor
252
Look at `/lang/python/apps/reader_test_subscribe.py` for a full example.
253
254 1a02be05 Nitesh Mor
## Reading multiple records at a time
255 8949c8d7 Nitesh Mor
256
Reading one record at a time can be very inefficient, especially when reading
257 1a02be05 Nitesh Mor
large amount of data. For this, we support asynchronous reads to read a range of
258
records at a time. The interface is similar to `subscribe_by_recno` in some
259
sense--events are returned as a result of an asynchronous call. 
260 8949c8d7 Nitesh Mor
261 1a02be05 Nitesh Mor
Look at `/lang/python/apps/reader_test_async.py` for a full example.
262 8949c8d7 Nitesh Mor
263
264
## Asynchronous write
265
266
*Partially implemented*. In the normal `append` call above, a client sends some
267
data to the log-server and waits for an acknowledgement before returning
268
control back to the application. In order to convert this blocking operation to
269
a non-blocking operation, `append_async` could be used instead of regular
270
`append`.
271
272
Refer to the API documentation at `/lang/python/README` for more details.