2 # -*- coding: utf-8 -*-
7 import libelliptics_python
8 from libelliptics_python
import log_level
, command_flags
, io_flags
11 class NodeStatus(libelliptics_python
.dnet_node_status
):
13 return "<NodeStatus nflags:%x, status_flags:%x, log_mask:%x>" % (self
.nflags
, self
.status_flags
, self
.log_mask
)
16 class Id(libelliptics_python
.elliptics_id
):
19 It has 2 constructors:
21 Id(list_id, group type)
23 list_id - list of 64 bytes, id of the object itself
24 group - group ID of the object
30 class Range(libelliptics_python
.elliptics_range
):
32 Structure that describes range request
33 start, end - IDs of the start and the end of the range
34 offset, size - offset to read from and size of bytes to read, applied for each key
35 cflags - command flags like locking so on (default is 0, see cflags class for defenitions)
36 ioflags - command IO flags (default is 0, see ioflags class for definitions)
37 group - group ID of the object
43 class Logger(libelliptics_python
.elliptics_log_file
):
45 Logger, that needed in Node constructor
46 Constructor takes 2 arguments: log file name (default is "/dev/stderr")
47 and log level (default is log_level.error, see log_level class for definitions)
50 llevel
= log_level
.error
52 def __init__(self
, log_file_name
= "/dev/stderr", llevel
= log_level
.error
):
54 log_file_name - name of the log file, default value is "/dev/stderr"
55 log_level - logging level, see log_level class for definitions
57 self
.log_file_name
= log_file_name
59 super(Logger
, self
).__init
__(log_file_name
, llevel
)
61 def log(self
, message
, level
):
63 log some message into elliptics log file
64 message - text message
65 level - log level, default is log_level.error (see log_level class for definitions)
67 super(Logger
, self
).log(level
, message
)
70 return "<Logger log_file_name:\"%s\" log_level:%d>" % (self
.log_file_name
, self
.llevel
)
73 class Node(libelliptics_python
.elliptics_node_python
):
75 Main client class. Constructor takes 1 argument: Logger object
78 def __init__(self
, log
=None):
82 super(Node
, self
).__init
__(log
or Logger())
84 def add_remote(self
, addr
, port
, family
=2):
86 Add address of elliptics storage node and connect to it
87 Usually you do not want to exit if client failed to connect to remote node, so catch up exceptions
88 But if no remote nodes were successfully added (check get_routes()) then client should not continue
89 addr - storage address
91 family - IP protocol family: 2 for IPv4 (default value) and 10 for IPv6
93 super(Node
, self
).add_remote(addr
, port
, family
)
95 def add_groups(self
, groups
):
97 Set groups to work with
98 groups - list of groups
100 super(Node
, self
).add_groups(groups
)
104 return super(Node
, self
).get_groups()
106 def get_routes(self
):
111 list - list of node addresses
113 return super(Node
, self
).get_routes()
120 string - storage nodes statistics
122 return super(Node
, self
).stat_log()
124 def lookup_addr(self
, *args
, **kwargs
):
126 Lookup where key should be located by its ID or key and group_id pair
128 lookup_addr(key, group_id)
131 key - remote key name
133 id - object of Id class
136 string - node address
138 return super(Node
, self
).lookup_addr(*args
, **{})
140 def read_file(self
, key
, filename
, offset
= 0, size
= 0, column
= 0):
142 Read file from elliptics by name/ID
144 read_file(key, filename, offset, size, column)
145 read_file(id, filename, offset, size)
147 key - remote key name
148 column - column type (default is 0, 1 is reserved for metadata)
149 id - object of Id class
151 filename - name of local file where data will be saved
152 offset - read file from this offset (default 0)
153 size - number of bytes to read, 0 means whole file (default is 0)
155 if isinstance(key
, basestring
):
156 new_args
= [str(key
), filename
, offset
, size
, column
]
158 new_args
= [key
, filename
, offset
, size
]
160 super(Node
, self
).read_file(*new_args
)
162 def write_file(self
, key
, filename
, local_offset
= 0, offset
= 0, size
= 0, \
163 cflags
= command_flags
.default
, ioflags
= io_flags
.default
, column
= 0):
165 Write file into elliptics by name/ID
167 write_file(key, filename, local_offset, offset, size, cflags, ioflags, column)
168 write_file(id, filename, local_offset, offset, size, cflags, ioflags)
170 key - remote key name
171 column - column type (default is 0, 1 is reserved for metadata)
172 id - object of Id class
174 filename - name of local file
175 local_offset - read local file from this offset (default 0)
176 offset - write file from this offset (default 0)
177 size - number of bytes to write, 0 means whole file (default is 0)
178 cflags - command flags (default is 0, see command_flags class for definitions)
179 ioflags - command IO flags (default is 0, see io_flags class for definitions)
181 if isinstance(key
, basestring
):
182 new_args
= [str(key
), filename
, local_offset
, offset
, size
, cflags
, ioflags
, column
]
184 new_args
= [key
, filename
, local_offset
, offset
, size
, cflags
, ioflags
]
186 super(Node
, self
).read_file(*new_args
)
188 def _create_read_args(self
, key
, offset
= 0, size
= 0, cflags
= command_flags
.default
, ioflags
= io_flags
.default
, column
= 0):
189 if isinstance(key
, basestring
):
190 return [str(key
), offset
, size
, cflags
, ioflags
, column
]
192 return [key
, offset
, size
, cflags
, ioflags
]
194 def read_data(self
, key
, offset
= 0, size
= 0, cflags
= command_flags
.default
, ioflags
= io_flags
.default
, column
= 0):
196 Read data from elliptics by name/ID
198 read_data(key, offset, size, cflags, ioflags, column)
199 read_data(id, offset, size, cflags, ioflags)
201 key - remote key name
202 column - column type (default is 0, 1 is reserved for metadata)
203 id - object of Id class
205 offset - read file from this offset (default 0)
206 size - number of bytes to read, 0 means whole file (default is 0)
207 cflags - command flags (default is 0, see command_flags class for definitions)
208 ioflags - command IO flags (default is 0, see io_flags class for definitions)
211 string - key value content
213 return super(Node
, self
).read_data(*self
._create
_read
_args
(key
, offset
, size
, cflags
, ioflags
, column
))
217 def read_latest(self
, key
, offset
= 0, size
= 0, cflags
= command_flags
.default
, ioflags
= io_flags
.default
, column
= 0):
219 Read data from elliptics by name/ID with the latest update_date in metadata
221 read_latest(key, offset, size, cflags, ioflags, column)
222 read_latest(id, offset, size, cflags, ioflags)
224 key - remote key name
225 column - column type (default is 0, 1 is reserved for metadata)
226 id - object of Id class
228 offset - read file from this offset (default 0)
229 size - number of bytes to read, 0 means whole file (default is 0)
230 cflags - command flags flags (default is 0, see command_flags class for definitions)
231 ioflags - command IO flags (default is 0, see io_flags class for definitions)
234 string - key value content
236 return super(Node
, self
).read_latest(*self
._create
_read
_args
(key
, offset
, size
, cflags
, ioflags
, column
))
238 def create_write_args(self
, key
, data
, offset
, ioflags
, cflags
, column
):
239 if isinstance(key
, basestring
):
240 return [str(key
), data
, offset
, cflags
, ioflags
, column
]
242 return [key
, data
, offset
, cflags
, ioflags
]
244 def write_data(self
, key
, data
, offset
= 0, cflags
= command_flags
.default
, ioflags
= io_flags
.default
, column
= 0):
246 Write data into elliptics by name/ID
248 write_data(key, data, offset, cflags, ioflags, column)
249 write_data(id, data, offset, cflags, ioflags)
251 key - remote key name
252 column - column type (default is 0, 1 is reserved for metadata)
253 id - object of Id class
255 data - data to be written
256 offset - write data in remote from this offset (default 0)
257 cflags - command flags flags (default is 0, see command_flags class for definitions)
258 ioflags - command IO flags (default is 0, see io_flags class for definitions)
261 string - nodes and paths where data was stored
263 return super(Node
, self
).write_data(*self
.create_write_args(key
, data
, offset
, ioflags
, cflags
, column
))
265 def write_metadata(self
, key
, cflags
= command_flags
.default
, name
= None, groups
= None):
267 Write metadata into elliptics by name/ID
269 write_metadata(key, cflags)
270 write_metadata(id, name, groups, cflags)
272 key - remote key name
273 id - object of Id class
276 groups - groups where data was stored
277 cflags - command flags (default is 0, see command_flags class for definitions)
279 if isinstance(key
, basestring
):
280 new_args
= [str(key
), cflags
]
282 new_args
= [key
, name
, groups
, cflags
]
284 super(Node
, self
).write_metadata(*new_args
)
286 def write(self
, key
, data
):
290 self
.write_data(key
, data
)
291 self
.write_metadata(key
)
293 def remove(self
, key
, cflags
= command_flags
.default
, ioflags
= io_flags
.default
, column
= 0):
295 Remove key by name/ID
297 remove(key, cflags, ioflags, column)
298 remove(id, cflags, ioflags)
300 key - remote key name
301 column - column type (default is 0, 1 is reserved for metadata)
302 id - object of Id class
304 cflags - command flags flags (default is 0, see command_flags class for definitions)
305 ioflags - command IO flags (default is 0, see io_flags class for definitions)
307 if isinstance(key
, basestring
):
308 new_args
= [str(key
), cflags
, ioflags
, column
]
310 new_args
= [key
, cflags
, ioflags
]
312 super(Node
, self
).remove(*new_args
)
314 def execute(self
, *args
, **kwargs
):
316 Execite server-side script
318 exec(id, event, data, binary)
319 exec(key, event, data, binary)
320 exec(event, data, binary)
322 key - remote key name
323 id - object of Id class
325 event - server-side event name
326 data - data for given event
327 binary - binary data (its logical meaning is the same as for data, it was added for convenience)
329 If execute() is called with 3 arguments script will be started on all storage nodes.
330 If id or key is specified script will be started on the node which hosts given key/id.
333 string - result of the script execution
335 return super(Node
, self
).execute(*args
, **{})
337 def update_status(self
, key
, status
= None, update
= 0):
339 Update elliptics status and log mask
341 update_status(id, status, update)
342 update_status((addr, port, family), status, update)
344 key - remote key name
345 id - object of Id class
347 addr - storage address
349 family - IP protocol family: 2 for IPv4 (default value) and 10 for IPv6
350 status - new node status, object of NodeStatus class
351 update - update status or just return current (default is 0)
353 If update = 0 status will not be changed
356 NodeStatus - current node status
358 status
= status
or NodeStatus()
359 if hasattr(key
, '__iter__'):
360 new_args
= (key
[0], key
[1], key
[2], status
, update
)
362 new_args
= (key
, status
, update
)
364 ret
= super(Node
, self
).update_status(*new_args
)
365 ret
.__class
__ = NodeStatus
368 def bulk_read(self
, keys
, cflags
= command_flags
.default
, raw
=False):
370 Bulk read keys from elliptics
371 keys - list of keys by name
372 cflags - command flags (default is 0, see command_flags class for definitions)
375 dict: key - original key, value - data itself
376 if raw is True: list - list of strings, each string consists of 64 byte key (sha-512 of original key), 8 byte data length and data itself
378 if type(keys
) in set([tuple, list, set, dict]):
381 rv
= super(Node
, self
).bulk_read(keys
, cflags
)
389 keys
= dict([(hashlib
.sha512(key
).hexdigest(), key
) for key
in keys
])
393 key
= binascii
.hexlify(r
[:64])
394 data_len
= struct
.unpack('Q', r
[64:72])[0]
395 data
= struct
.unpack("%ss" % data_len
, r
[72:72 + data_len
])[0]
396 rv_dict
[keys
[key
]] = data
401 def read_data_range(self
, read_range
):
403 Read keys from elliptics by range of IDs
404 read_range - object of Range class
407 list - list of strings, each string consists of 64 byte key, 8 byte data length and data itself
409 return super(Node
, self
).read_data_range(read_range
)