def frozen(self, args): """Make device readonly""" dev = self._get_device(args.path) id = dev.config.id if id not in self._devices: raise IOError('not found') messager.call(config.storage_server_address, 'storage.frozen', did = id) dev.config.mode = 'frozen' dev.flush() return 'ok'
def offline(self, args): """Offline device, data on this device is not available anymore unless you online it again. You can decide whether to replicate data first.""" dev = self._get_device(args.path) id = dev.config.id if id not in self._devices: raise IOError('not found') messager.call(config.storage_server_address, 'storage.offline', did = id, replicate = False) dev.flush() del self._devices[id] self._flush() return 'ok'
def _heartbeat(self): """Heartbeat message to storage server upstream: devices infos such as size, used change downstream: deleted chunks """ while True: # Lock tmp = self._devices_changed self._devices_changed = [] confs = {} # Unlock # Read newest status of devs # changed = {} for did in tmp: try: confs[did] = self._lookup_dev(did).config except: continue rc = messager.call(config.storage_server_address, 'storage.heartbeat', addr = self._addr, confs = confs) if rc.needreport: # Start another thread to send chunk reports thread.start_new_thread(self._send_chunk_reports, ()) # Delete old chunks for did, chunks in rc.deleted_chunks.items(): try: dev = self._lookup_dev(did) except: continue self._mark_changed(did) self._chunk_shard.delete_chunks(chunks, dev) time.sleep(5)
def online(self, args): """Online device, send reports to storage server The 'online' status information is only maintained by storage server. """ dev = self._get_device(args.path) id = dev.config.id if id not in self._devices: self._devices[id] = dev.config.path # Add entry if dev.config.type != 'chunk': raise IOError('wrong type') compressed_report = zlib.compress(pformat(self._get_chunks(dev))) messager.call(config.storage_server_address, 'storage.online', conf = dev.config, addr = config.chunk_server_address, payload = compressed_report) dev.flush() self._flush() return 'ok'
def delete(self, req): """Delete file, store the free chunks to file 'deleted_chunks', tell it to storage manager in next hb message There shall be a .trash dir to store it first, auto delete 30 days later @file note that root can't be deleted @recursive bool return ok """ req.file = os.path.normpath(req.file) if req.file == '/': self._error('attempt to delete root') parent = self._lookup(os.path.dirname(req.file)) name = os.path.basename(req.file) if not parent or name not in parent.children: self._error('no such file or directory') obj = self._object_shard.load_object(parent.children[name]) if obj: if obj.type == 'dir': if len(obj.children) > 2: if not req.recursive: self._error('dir not empty') # Delete dir recursively deleted = self._delete_recursive(obj) #Delete file if obj.type == 'file': deleted = self._delete_file(obj) else: # Shall we return error? #self._error('file object missing') pass # Delete entry in parent del parent.children[name] self._object_shard.store_object(parent) # Free chunks to storage, this should be done in another thread messager.call(config.storage_server_address, 'storage.free', deleted = deleted) return 'ok'
def status(self, args): """Show storage status all status of the global pool local status of all local devs /data/sda status of a local dev id # TODO: get disks info on remote chunk servers First lookup in local then in storage server """ if args.path == 'local': for did, path in self._devices.items(): print did, path elif args.path == 'all': status = messager.call(config.storage_server_address, 'storage.status') for k in status.nodes.keys(): node = status.nodes[k] print '%s:%d' % (k[0], k[1]), time.ctime(node.update_time) for did in node.devs: print ' ', self._print_device(OODict(status.devices[did].conf)) else: dev = self._get_device(args.path) self._print_device(dev.config)