X-Git-Url: https://git.distorted.org.uk/~mdw/rhodes/blobdiff_plain/94fae73cdb244368c2f92cf82badfc0ecb56c541..ba147940be8c2b94c16ce12979d5fe92b2d6a9d1:/rhodes diff --git a/rhodes b/rhodes index 8509a4f..01a7aad 100755 --- a/rhodes +++ b/rhodes @@ -1,4 +1,28 @@ #! /usr/bin/python +### -*-python-*- +### +### Calculate discrete logs in groups +### +### (c) 2017 Mark Wooding +### + +###----- Licensing notice --------------------------------------------------- +### +### This file is part of Rhodes, a distributed discrete-log finder. +### +### Rhodes is free software; you can redistribute it and/or modify +### it under the terms of the GNU General Public License as published by +### the Free Software Foundation; either version 2 of the License, or +### (at your option) any later version. +### +### Rhodes is distributed in the hope that it will be useful, +### but WITHOUT ANY WARRANTY; without even the implied warranty of +### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +### GNU General Public License for more details. +### +### You should have received a copy of the GNU General Public License +### along with Rhodes; if not, write to the Free Software Foundation, +### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. from sys import argv, stdout, stderr, exit import errno as E @@ -11,9 +35,15 @@ import signal as SIG import catacomb as C import sqlite3 as SQL +###-------------------------------------------------------------------------- +### Miscellaneous utilities. + class ExpectedError (Exception): pass +###-------------------------------------------------------------------------- +### Database handling. + CONNINIT_SQL = """ PRAGMA foreign_keys = on; """ @@ -54,6 +84,16 @@ CREATE TABLE points FOREIGN KEY (p, k) REFERENCES progress (p, k)); """ +def connect_db(dir): + db = SQL.connect(OS.path.join(dir, 'db')) + db.text_factory = str + c = db.cursor() + c.executescript(CONNINIT_SQL) + return db + +###-------------------------------------------------------------------------- +### Group support. + GROUPMAP = {} class GroupClass (type): @@ -96,6 +136,9 @@ class BinaryFieldUnitGroup (BaseGroup): def getgroup(kind, desc): return GROUPMAP[kind](desc) +###-------------------------------------------------------------------------- +### Number-theoretic utilities. + def factor(n): ff = [] proc = S.Popen(['./factor', str(n)], stdout = S.PIPE) @@ -106,6 +149,9 @@ def factor(n): if rc: raise ExpectedError, 'factor failed: rc = %d' % rc return ff +###-------------------------------------------------------------------------- +### Command dispatch. + CMDMAP = {} def defcommand(f, name = None): @@ -116,12 +162,67 @@ def defcommand(f, name = None): CMDMAP[name] = f return f -def connect_db(dir): - db = SQL.connect(OS.path.join(dir, 'db')) - db.text_factory = str +###-------------------------------------------------------------------------- +### Job status utilities. + +def get_top(db): c = db.cursor() - c.executescript(CONNINIT_SQL) - return db + c.execute("""SELECT kind, groupdesc, g, x, m, n FROM top""") + kind, groupdesc, gstr, xstr, mstr, nstr = c.fetchone() + G = getgroup(kind, groupdesc) + g, x, m = G.elt(gstr), G.elt(xstr), C.MP(mstr) + n = nstr is not None and C.MP(nstr) or None + return G, g, x, m, n + +def get_job(db): + c = db.cursor() + c.execute("""SELECT p.p, p.e, p.k, p.n, p.dpbits + FROM progress AS p LEFT OUTER JOIN workers AS w + ON p.p = w.p and p.k = w.k + WHERE p.k < p.e AND (p.dpbits > 0 OR w.pid IS NULL) + LIMIT 1""") + row = c.fetchone() + if row is None: return None, None, None, None, None + else: + pstr, e, k, nstr, dpbits = row + p, n = C.MP(pstr), C.MP(nstr) + return p, e, k, n, dpbits + +def maybe_cleanup_worker(dir, db, pid): + c = db.cursor() + f = OS.path.join(dir, 'lk.%d' % pid) + state = 'LIVE' + try: fd = OS.open(f, OS.O_WRONLY) + except OSError, err: + if err.errno != E.ENOENT: raise ExpectedError, 'open lockfile: %s' % err + state = 'STALE' + else: + try: F.lockf(fd, F.LOCK_EX | F.LOCK_NB) + except IOError, err: + if err.errno != E.EAGAIN: raise ExpectedError, 'check lock: %s' % err + else: + state = 'STALE' + if state == 'STALE': + try: OS.unlink(f) + except OSError: pass + c.execute("""DELETE FROM workers WHERE pid = ?""", (pid,)) + +def maybe_kill_worker(dir, pid): + f = OS.path.join(dir, 'lk.%d' % pid) + try: fd = OS.open(f, OS.O_RDWR) + except OSError, err: + if err.errno != E.ENOENT: raise ExpectedError, 'open lockfile: %s' % err + return + try: F.lockf(fd, F.LOCK_EX | F.LOCK_NB) + except IOError, err: + if err.errno != E.EAGAIN: raise ExpectedError, 'check lock: %s' % err + else: return + OS.kill(pid, SIG.SIGTERM) + try: OS.unlink(f) + except OSError: pass + +###-------------------------------------------------------------------------- +### Setup. @defcommand def setup(dir, kind, groupdesc, gstr, xstr): @@ -166,14 +267,8 @@ def setup(dir, kind, groupdesc, gstr, xstr): c.execute("""INSERT INTO progress (p, e, dpbits) VALUES (?, ?, ?)""", (str(p), e, dpbits)) -def get_top(db): - c = db.cursor() - c.execute("""SELECT kind, groupdesc, g, x, m, n FROM top""") - kind, groupdesc, gstr, xstr, mstr, nstr = c.fetchone() - G = getgroup(kind, groupdesc) - g, x, m = G.elt(gstr), G.elt(xstr), C.MP(mstr) - n = nstr is not None and C.MP(nstr) or None - return G, g, x, m, n +###-------------------------------------------------------------------------- +### Check. @defcommand def check(dir): @@ -239,19 +334,8 @@ def check(dir): exit(rc[0]) -def get_job(db): - c = db.cursor() - c.execute("""SELECT p.p, p.e, p.k, p.n, p.dpbits - FROM progress AS p LEFT OUTER JOIN workers AS w - ON p.p = w.p and p.k = w.k - WHERE p.k < p.e AND (p.dpbits > 0 OR w.pid IS NULL) - LIMIT 1""") - row = c.fetchone() - if row is None: return None, None, None, None, None - else: - pstr, e, k, nstr, dpbits = row - p, n = C.MP(pstr), C.MP(nstr) - return p, e, k, n, dpbits +###-------------------------------------------------------------------------- +### Done. @defcommand def done(dir): @@ -265,38 +349,8 @@ def done(dir): if p is None: exit(2) else: exit(1) -def maybe_cleanup_worker(dir, db, pid): - c = db.cursor() - f = OS.path.join(dir, 'lk.%d' % pid) - state = 'LIVE' - try: fd = OS.open(f, OS.O_WRONLY) - except OSError, err: - if err.errno != E.ENOENT: raise ExpectedError, 'open lockfile: %s' % err - state = 'STALE' - else: - try: F.lockf(fd, F.LOCK_EX | F.LOCK_NB) - except IOError, err: - if err.errno != E.EAGAIN: raise ExpectedError, 'check lock: %s' % err - else: - state = 'STALE' - if state == 'STALE': - try: OS.unlink(f) - except OSError: pass - c.execute("""DELETE FROM workers WHERE pid = ?""", (pid,)) - -def maybe_kill_worker(dir, pid): - f = OS.path.join(dir, 'lk.%d' % pid) - try: fd = OS.open(f, OS.O_RDWR) - except OSError, err: - if err.errno != E.ENOENT: raise ExpectedError, 'open lockfile: %s' % err - return - try: F.lockf(fd, F.LOCK_EX | F.LOCK_NB) - except IOError, err: - if err.errno != E.EAGAIN: raise ExpectedError, 'check lock: %s' % err - else: return - OS.kill(pid, SIG.SIGTERM) - try: OS.unlink(f) - except OSError: pass +###-------------------------------------------------------------------------- +### Step. @defcommand def step(dir, cmd, *args): @@ -516,6 +570,9 @@ def step(dir, cmd, *args): with db: c.execute("""DELETE FROM workers WHERE pid = ?""", (mypid,)) +###-------------------------------------------------------------------------- +### Top-level program. + PROG = argv[0] try: