source: sage/dsage/database/job.py @ 3852:fd7b59af8402

Revision 3852:fd7b59af8402, 10.5 KB checked in by Yi Qiang <yqiang@…>, 6 years ago (diff)

changed job.id to job.job_id for consistency.

Line 
1############################################################################
2#                                                                     
3#   DSAGE: Distributed SAGE                     
4#                                                                             
5#       Copyright (C) 2006, 2007 Yi Qiang <yqiang@gmail.com>               
6#                                                                           
7#  Distributed under the terms of the GNU General Public License (GPL)       
8#
9#    This code is distributed in the hope that it will be useful,
10#    but WITHOUT ANY WARRANTY; without even the implied warranty of
11#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12#    General Public License for more details.
13#
14#  The full text of the GPL is available at:
15#
16#                  http://www.gnu.org/licenses/
17#
18############################################################################
19
20import datetime
21import cPickle
22import zlib
23import bz2
24import os
25import copy
26
27from persistent import Persistent
28
29class Job(Persistent):
30    r"""
31    Defines a Job that gets distributed to clients.
32   
33    """
34
35    def __init__(self, id_=None, name=None, code=None, parent=None, 
36                 username=None, type_='sage'):
37        r"""
38        Creates a new job.
39
40        Parameters:
41        name -- job name
42        id -- job id (must be unique)
43        code -- job code
44        parent -- sets if the job is a parent job
45        username -- author of the job (not neccesarily unique)
46        type -- the type of the job (file, string, generator)
47                defaults to string
48
49        """
50
51        self.jdict = {}
52
53        # Job keywords
54        self.jdict['job_id'] = id_
55        self.jdict['name'] = name
56        self.jdict['code'] = code
57        self.jdict['username'] = username
58        self.jdict['data'] = []
59        self.jdict['output'] = ''
60        self.jdict['worker_info'] = None
61        # Valid status keywords:
62        # new, completed, incomplete, processing
63        self.jdict['status'] = 'new' 
64        self.jdict['creation_time'] = datetime.datetime.now()
65        self.jdict['update_time'] = None
66        self.jdict['finish_time'] = None
67        self.jdict['killed'] = False
68        self.jdict['type'] = type_
69        self.jdict['result'] = None # result should be a pickled object
70        self.jdict['failures'] = 0
71        self.jdict['verifiable'] = False # is this job easily verified?
72       
73        # These might become deprecated
74        self.jdict['parent'] = parent
75        self.jdict['children'] = []
76
77    def __str__(self):
78        return str(self.jdict)
79   
80    def num_of_children(self):
81        return len(self.jdict['children'])
82
83    def get_name(self):
84        return self.jdict['name']
85    def set_name(self, value):
86        if not isinstance(value, str):
87            raise TypeError
88        self.jdict['name'] = value
89    name = property(fget=get_name, fset=set_name, fdel=None, doc='Job name')
90
91    def get_code(self):
92        return self.jdict['code']
93    def set_code(self, value):
94        if not isinstance(value, str):
95            raise TypeError
96        self.jdict['code'] = value
97    code = property(fget=get_code, fset=set_code, fdel=None,
98                    doc='Job code')
99
100    def get_id(self):
101        return self.jdict['job_id']
102    def set_id(self, value):
103        if not isinstance(value, str):
104            raise TypeError
105        self.jdict['job_id'] = value
106    job_id = property(fget=get_id, fset=set_id, fdel=None, doc='Job ID')
107   
108    def get_status(self):
109        return self.jdict['status']
110    def set_status(self, value):
111        # statuses = ['new', 'completed', 'incomplete', 'processing']
112        # if not value in statuses:
113        #    raise TypeError
114        #if value == 'completed':
115        #    self.finish_time = datetime.datetime.now()
116        self.jdict['status'] = value
117    status = property(fget=get_status, fset=set_status, fdel=None, 
118                      doc='Job status')
119   
120    def get_result(self):
121        # loads the result
122        try:
123            result = cPickle.loads(self.jdict['result'])
124        except Exception, msg1:
125            try:
126                result = cPickle.loads(zlib.decompress(self.jdict['result']))
127            except Exception, msg2:
128                try:
129                    result = cPickle.loads(bz2.decompress(self.jdict['result']))
130                except:
131                    result = self.jdict['result']
132        return result
133    def set_result(self, value):
134        self.jdict['result'] = value
135    result = property(fget=get_result, fset=set_result, fdel=None, 
136                      doc='Job result')
137   
138    def get_data(self):
139       return self.jdict['data']
140    def set_data(self, value):
141       self.jdict['data'] = value
142    data = property(fget=get_data, fset=set_data, fdel=None,
143                  doc='Job data')
144
145    def get_output(self):
146        return self.jdict['output']
147    def set_output(self, value):
148        self.jdict['output'] = value
149    output = property(fget=get_output, fset=set_output, fdel=None,
150                      doc='Job output')
151
152    def get_username(self):
153        return self.jdict['username']
154    def set_username(self, value):
155        self.jdict['username'] = value
156    username = property(fget=get_username, fset=set_username, fdel=None,
157                      doc='Job author')
158   
159    def get_finish_time(self):
160        return self.jdict['finish_time']
161    def set_finish_time(self, value):
162        if not isinstance(value, datetime.datetime):
163            raise TypeError
164        self.jdict['finish_time'] = value
165    finish_time = property(fget=get_finish_time, fset=set_finish_time, 
166                           fdel=None, doc='Job finish time')
167
168    def get_update_time(self):
169        return self.jdict['update_time']
170    def set_update_time(self, value):
171        if not isinstance(value, datetime.datetime):
172            raise TypeError
173        self.jdict['update_time'] = value
174    update_time = property(fget=get_update_time, fset=set_update_time,
175                            fdel=None, doc='Job updated time')
176   
177    def get_creation_time(self):
178        return self.jdict['creation_time']
179
180    def set_creation_time(self, value):
181        if not isinstance(value, datetime.datetime):
182            raise TypeError
183        self.jdict['creation_time'] = value
184    creation_time = property(fget=get_creation_time, fset=set_creation_time,
185                             fdel=None, doc='Job creation time')
186
187    def get_type(self):
188        return self.jdict['type']
189    def set_type(self, value):
190        types = ['sage', 'spyx', 'py']
191        if value not in types:
192            raise TypeError
193
194        self.jdict['type'] = value
195    type = property(fget=get_type, fset=set_type,
196                    fdel=None, doc='Job type')
197
198    def get_failures(self):
199        return self.jdict['failures']
200    def set_failures(self, value):
201        if not isinstance(value, int):
202            raise TypeError
203        self.jdict['failures'] = value
204    failures = property(fget=get_failures, fset=set_failures,
205                        fdel=None, doc='Number of failures')
206
207    def get_killed(self):
208        return self.jdict['killed']
209    def set_killed(self, value):
210        if not isinstance(value, bool):
211            raise TypeError
212        self.jdict['killed'] = value
213    killed = property(fget=get_killed, fset=set_killed, 
214                      fdel=None, doc='Job killed status')
215
216    def get_worker_info(self):
217        return self.jdict['worker_info']
218    def set_worker_info(self, value):
219        self.jdict['worker_info'] = value
220    worker_info = property(fget=get_worker_info, fset=set_worker_info,
221                           fdel=None, doc='Worker info')
222     
223    def get_verifiable(self):
224        return self.jdict['verifiable']
225    def set_verifiable(self, value):
226        if not isinstance(value, bool):
227            raise TypeError
228        self.jdict['verifiable'] = value         
229   
230    def attach(self, var, obj, file_name=None):
231        r"""
232        Attaches an object to a job.
233       
234        Parameters:
235        var -- the variable name you'd like the worker to use
236        obj -- the object you want to attach
237        filename -- optional, if your object is a saved sobj
238       
239        """
240       
241        if file_name:
242            try:
243                s = open(file_name, 'rb').read()
244                s = zlib.compress(s)
245            except:
246                print 'Unable to load %s. ' % file_name
247                return
248        else:
249            try:
250                s = cPickle.dumps(obj, 2)
251                s = zlib.compress(s)
252            except cPickle.PicklingError:
253                print 'Unable to attach your object.'
254                return
255        self.jdict['data'].append((var, s, 'object'))
256       
257    def attach_file(self, file_name):
258        r"""
259        Attach a file to a job.
260       
261        Parameters:
262        file_name -- obvious
263       
264        """
265       
266        try:
267            f = open(file_name, 'rb').read()
268            f = zlib.compress(f)
269        except:
270            print 'Unable to read file.'
271            return
272       
273        # Strip out any hard coded path in the file name
274        file_name = os.path.split(file_name)[1]
275        self.jdict['data'].append((file_name, f, 'file'))
276   
277    def pickle(self):
278        r"""
279        Returns a pickled representation of self.
280       
281        """
282       
283        try:
284            s = cPickle.dumps(self, 2)
285            s = zlib.compress(s)
286        except:
287            print 'Error pickling self'
288            return
289        return s
290   
291    def unpickle(self, pickled_job):
292        r"""
293        Returns the unpickled version of myself.
294       
295        """
296       
297        return cPickle.loads(zlib.decompress(pickled_job))
298   
299    def reduce(self):
300        r"""
301        Returns a reduced form of Job.jdict to be sent over the network.
302       
303        """
304       
305        # TODO: Figure out what attributes are safe to delete
306       
307        # dump and compress the data of the job
308        jdict = copy.deepcopy(self.jdict)
309        jdict['data'] = cPickle.dumps(self.jdict['data'], 2)
310        jdict['data'] = zlib.compress(jdict['data'])
311       
312        return jdict
313
314def expand_job(jdict):
315    r"""
316    This method recreates a Job object given a jdict.
317   
318    """
319   
320    if jdict is None:
321        return None
322   
323    job = Job()
324   
325    # decompress and load data
326    try:
327        jdict['data'] = zlib.decompress(jdict['data'])
328        jdict['data'] = cPickle.loads(jdict['data'])
329    except:
330        jdict['data'] = None
331    # swap the jdicts, easy eh?
332    job.jdict.update(jdict)
333   
334    return job
Note: See TracBrowser for help on using the repository browser.