Compare commits

...

12 Commits

Author SHA1 Message Date
7d7b89b52f Add --no-decim option to nilmtool list 2013-08-12 13:04:25 -04:00
8d249273c6 Change -V option to -v everywhere 2013-08-06 21:38:00 -04:00
abe431c663 Add verify_ssl option to HTTPClient 2013-08-06 12:39:32 -04:00
ccf1f695af Prevent negative numbers in dbinfo output.
This might occur if things change while we're calculating the sizes.
2013-08-05 12:25:36 -04:00
06f7390c9e Fix disk usage block size 2013-08-05 12:25:10 -04:00
6de77a08f1 Report actual disk size, not apparent size 2013-08-05 12:16:56 -04:00
8db9771c20 Remove leftover fsck test 2013-08-05 12:16:47 -04:00
04f815a24b Reorder nilmtool commands 2013-08-04 19:51:13 -04:00
6868f5f126 fsck: limit max retries so we don't get stuck in a loop forever 2013-08-03 22:34:30 -04:00
ca0943ec19 fsck: add --no-data option to do a quicker fsck
This makes it fast enough to run at startup with -f, if it's expected
that a system will frequently need to be fixed.
2013-08-03 22:31:45 -04:00
68addb4e4a Clarify output when fsck database is locked 2013-08-03 21:58:24 -04:00
68c33b1f14 fsck: add comma separator on big numbers 2013-08-03 21:50:33 -04:00
9 changed files with 39 additions and 30 deletions

View File

@@ -1,5 +1,5 @@
# By default, run the tests. # By default, run the tests.
all: fscktest all: test
version: version:
python setup.py version python setup.py version
@@ -23,10 +23,6 @@ docs:
lint: lint:
pylint --rcfile=.pylintrc nilmdb pylint --rcfile=.pylintrc nilmdb
fscktest:
python -c "import nilmdb.fsck; nilmdb.fsck.Fsck('/home/jim/wsgi/db').check()"
# python -c "import nilmdb.fsck; nilmdb.fsck.Fsck('/home/jim/mnt/bucket/mnt/sharon/data/db', True).check()"
test: test:
ifeq ($(INSIDE_EMACS), t) ifeq ($(INSIDE_EMACS), t)
# Use the slightly more flexible script # Use the slightly more flexible script

View File

@@ -9,7 +9,7 @@ import requests
class HTTPClient(object): class HTTPClient(object):
"""Class to manage and perform HTTP requests from the client""" """Class to manage and perform HTTP requests from the client"""
def __init__(self, baseurl = "", post_json = False): def __init__(self, baseurl = "", post_json = False, verify_ssl = True):
"""If baseurl is supplied, all other functions that take """If baseurl is supplied, all other functions that take
a URL can be given a relative URL instead.""" a URL can be given a relative URL instead."""
# Verify / clean up URL # Verify / clean up URL
@@ -19,6 +19,7 @@ class HTTPClient(object):
self.baseurl = reparsed.rstrip('/') + '/' self.baseurl = reparsed.rstrip('/') + '/'
# Build Requests session object, enable SSL verification # Build Requests session object, enable SSL verification
self.verify_ssl = verify_ssl
self.session = requests.Session() self.session = requests.Session()
self.session.verify = True self.session.verify = True
@@ -67,7 +68,8 @@ class HTTPClient(object):
params = query_data, params = query_data,
data = body_data, data = body_data,
stream = stream, stream = stream,
headers = headers) headers = headers,
verify = self.verify_ssl)
except requests.RequestException as e: except requests.RequestException as e:
raise ServerError(status = "502 Error", url = url, raise ServerError(status = "502 Error", url = url,
message = str(e.message)) message = str(e.message))

View File

@@ -19,9 +19,8 @@ except ImportError: # pragma: no cover
# Valid subcommands. Defined in separate files just to break # Valid subcommands. Defined in separate files just to break
# things up -- they're still called with Cmdline as self. # things up -- they're still called with Cmdline as self.
subcommands = [ "help", "info", "create", "list", "metadata", subcommands = [ "help", "info", "create", "rename", "list", "intervals",
"insert", "extract", "remove", "destroy", "metadata", "insert", "extract", "remove", "destroy" ]
"intervals", "rename" ]
# Import the subcommand modules # Import the subcommand modules
subcmd_mods = {} subcmd_mods = {}
@@ -122,7 +121,7 @@ class Cmdline(object):
group = self.parser.add_argument_group("General options") group = self.parser.add_argument_group("General options")
group.add_argument("-h", "--help", action='help', group.add_argument("-h", "--help", action='help',
help='show this help message and exit') help='show this help message and exit')
group.add_argument("-V", "--version", action="version", group.add_argument("-v", "--version", action="version",
version = nilmdb.__version__) version = nilmdb.__version__)
group = self.parser.add_argument_group("Server") group = self.parser.add_argument_group("Server")

View File

@@ -45,6 +45,8 @@ def setup(self, sub):
help="Show raw timestamps when printing times") help="Show raw timestamps when printing times")
group.add_argument("-l", "--layout", action="store_true", group.add_argument("-l", "--layout", action="store_true",
help="Show layout type next to path name") help="Show layout type next to path name")
group.add_argument("-n", "--no-decim", action="store_true",
help="Skip paths containing \"~decim-\"")
return cmd return cmd
@@ -71,6 +73,8 @@ def cmd_list(self):
(path, layout, int_min, int_max, rows, time) = stream[:6] (path, layout, int_min, int_max, rows, time) = stream[:6]
if not fnmatch.fnmatch(path, argpath): if not fnmatch.fnmatch(path, argpath):
continue continue
if self.args.no_decim and "~decim-" in path:
continue
if self.args.layout: if self.args.layout:
printf("%s %s\n", path, layout) printf("%s %s\n", path, layout)

View File

@@ -44,15 +44,16 @@ def err(format, *args):
fprintf(sys.stderr, format, *args) fprintf(sys.stderr, format, *args)
# Decorator that retries a function if it returns a specific value # Decorator that retries a function if it returns a specific value
def retry_if_raised(exc, message = None): def retry_if_raised(exc, message = None, max_retries = 100):
def f1(func): def f1(func):
def f2(*args, **kwargs): def f2(*args, **kwargs):
while True: for n in range(max_retries):
try: try:
return func(*args, **kwargs) return func(*args, **kwargs)
except exc as e: except exc as e:
if message: if message:
log("%s\n\n", message) log("%s\n\n", message)
raise Exception("Max number of retries (%d) exceeded; giving up")
return f2 return f2
return f1 return f1
@@ -89,7 +90,7 @@ class Fsck(object):
### Main checks ### Main checks
@retry_if_raised(RetryFsck, "Something was fixed: restarting fsck") @retry_if_raised(RetryFsck, "Something was fixed: restarting fsck")
def check(self): def check(self, skip_data = False):
self.bulk = None self.bulk = None
self.sql = None self.sql = None
try: try:
@@ -97,7 +98,10 @@ class Fsck(object):
self.check_sql() self.check_sql()
self.check_streams() self.check_streams()
self.check_intervals() self.check_intervals()
self.check_data() if skip_data:
log("skipped data check\n")
else:
self.check_data()
finally: finally:
if self.bulk: if self.bulk:
self.bulk.close() self.bulk.close()
@@ -118,7 +122,11 @@ class Fsck(object):
raise FsckError("Bulk data directory missing (%s)", self.bulkpath) raise FsckError("Bulk data directory missing (%s)", self.bulkpath)
with open(self.bulklock, "w") as lockfile: with open(self.bulklock, "w") as lockfile:
if not nilmdb.utils.lock.exclusive_lock(lockfile): if not nilmdb.utils.lock.exclusive_lock(lockfile):
raise FsckError('database already locked by another process') raise FsckError('Database already locked by another process\n'
'Make sure all other processes that might be '
'using the database are stopped.\n'
'Restarting apache will cause it to unlock '
'the db until a request is received.')
# unlocked immediately # unlocked immediately
self.bulk = nilmdb.server.bulkdata.BulkData(self.basepath) self.bulk = nilmdb.server.bulkdata.BulkData(self.basepath)
@@ -170,7 +178,7 @@ class Fsck(object):
def check_streams(self): def check_streams(self):
ids = self.stream_path.keys() ids = self.stream_path.keys()
log("checking %d streams\n", len(ids)) log("checking %s streams\n", "{:,d}".format(len(ids)))
with Progress(len(ids)) as pbar: with Progress(len(ids)) as pbar:
for i, sid in enumerate(ids): for i, sid in enumerate(ids):
pbar.update(i) pbar.update(i)
@@ -306,7 +314,7 @@ class Fsck(object):
def check_intervals(self): def check_intervals(self):
total_ints = sum(len(x) for x in self.stream_interval.values()) total_ints = sum(len(x) for x in self.stream_interval.values())
log("checking %d intervals\n", total_ints) log("checking %s intervals\n", "{:,d}".format(total_ints))
done = 0 done = 0
with Progress(total_ints) as pbar: with Progress(total_ints) as pbar:
for sid in self.stream_interval: for sid in self.stream_interval:
@@ -389,7 +397,7 @@ class Fsck(object):
def check_data(self): def check_data(self):
total_rows = sum(sum((y[3] - y[2]) for y in x) total_rows = sum(sum((y[3] - y[2]) for y in x)
for x in self.stream_interval.values()) for x in self.stream_interval.values())
log("checking %d rows of data\n", total_rows) log("checking %s rows of data\n", "{:,d}".format(total_rows))
done = 0 done = 0
with Progress(total_rows) as pbar: with Progress(total_rows) as pbar:
for sid in self.stream_interval: for sid in self.stream_interval:

View File

@@ -10,16 +10,17 @@ def main():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description = 'Check database consistency', description = 'Check database consistency',
formatter_class = argparse.ArgumentDefaultsHelpFormatter) formatter_class = argparse.ArgumentDefaultsHelpFormatter,
parser.add_argument("-V", "--version", action="version", version = nilmdb.__version__)
version = nilmdb.__version__)
parser.add_argument("-f", "--fix", action="store_true", parser.add_argument("-f", "--fix", action="store_true",
default=False, help = 'Fix errors when possible ' default=False, help = 'Fix errors when possible '
'(which may involve removing data)') '(which may involve removing data)')
parser.add_argument("-n", "--no-data", action="store_true",
default=False, help = 'Skip the slow full-data check')
parser.add_argument('database', help = 'Database directory') parser.add_argument('database', help = 'Database directory')
args = parser.parse_args() args = parser.parse_args()
nilmdb.fsck.Fsck(args.database, args.fix).check() nilmdb.fsck.Fsck(args.database, args.fix).check(skip_data = args.no_data)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@@ -10,10 +10,8 @@ def main():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description = 'Run the NilmDB server', description = 'Run the NilmDB server',
formatter_class = argparse.ArgumentDefaultsHelpFormatter) formatter_class = argparse.ArgumentDefaultsHelpFormatter,
version = nilmdb.__version__)
parser.add_argument("-V", "--version", action="version",
version = nilmdb.__version__)
group = parser.add_argument_group("Standard options") group = parser.add_argument_group("Standard options")
group.add_argument('-a', '--address', group.add_argument('-a', '--address',

View File

@@ -74,8 +74,8 @@ class Root(NilmApp):
dbsize = nilmdb.utils.du(path) dbsize = nilmdb.utils.du(path)
return { "path": path, return { "path": path,
"size": dbsize, "size": dbsize,
"other": usage.used - dbsize, "other": max(usage.used - dbsize, 0),
"reserved": usage.total - usage.used - usage.free, "reserved": max(usage.total - usage.used - usage.free, 0),
"free": usage.free } "free": usage.free }
class Stream(NilmApp): class Stream(NilmApp):

View File

@@ -21,7 +21,8 @@ def du(path):
errors that might occur if we encounter broken symlinks or errors that might occur if we encounter broken symlinks or
files in the process of being removed.""" files in the process of being removed."""
try: try:
size = os.path.getsize(path) st = os.stat(path)
size = st.st_blocks * 512
if os.path.isdir(path): if os.path.isdir(path):
for thisfile in os.listdir(path): for thisfile in os.listdir(path):
filepath = os.path.join(path, thisfile) filepath = os.path.join(path, thisfile)