Example #1
0
// Decode job from byte slice
func decodeJob(data []byte) (job *Job, err error) {
	if len(data) < 12 {
		return nil, common.Errorf("Invalid data: %V", data)
	}
	datatype := common.BytesToUint32([4]byte{data[4], data[5], data[6], data[7]})
	l := common.BytesToUint32([4]byte{data[8], data[9], data[10], data[11]})
	if len(data[12:]) != int(l) {
		return nil, common.Errorf("Invalid data: %V", data)
	}
	data = data[12:]
	job = &Job{magicCode: common.RES, DataType: datatype, c: make(chan bool)}
	switch datatype {
	case common.JOB_ASSIGN:
		s := bytes.SplitN(data, []byte{'\x00'}, 3)
		if len(s) == 3 {
			job.Handle = string(s[0])
			job.Fn = string(s[1])
			data = s[2]
		}
	case common.JOB_ASSIGN_UNIQ:
		s := bytes.SplitN(data, []byte{'\x00'}, 4)
		if len(s) == 4 {
			job.Handle = string(s[0])
			job.Fn = string(s[1])
			job.UniqueId = string(s[2])
			data = s[3]
		}
	}
	job.Data = data
	return
}
Example #2
0
// Decode a job from byte slice
func decodeJob(data []byte) (job *Job, err error) {
	if len(data) < 12 {
		return nil, common.Errorf("Invalid data: %V", data)
	}
	datatype := common.BytesToUint32([4]byte{data[4], data[5], data[6], data[7]})
	l := common.BytesToUint32([4]byte{data[8], data[9], data[10], data[11]})
	if len(data[12:]) != int(l) {
		return nil, common.Errorf("Invalid data: %V", data)
	}
	data = data[12:]
	var handle string
	switch datatype {
	case common.WORK_DATA, common.WORK_WARNING, common.WORK_STATUS,
		common.WORK_COMPLETE, common.WORK_FAIL, common.WORK_EXCEPTION:
		i := bytes.IndexByte(data, '\x00')
		if i != -1 {
			handle = string(data[:i])
			data = data[i+1:]
		}
	}

	return &Job{magicCode: common.RES,
		DataType: datatype,
		Data:     data,
		Handle:   handle}, nil
}
Example #3
0
// Decode a job from byte slice
func decodeJob(data []byte) (job *Job, err error) {
	if len(data) < 12 {
		return nil, common.Errorf("Invalid data: %V", data)
	}
	datatype := common.BytesToUint32([4]byte{data[4], data[5], data[6], data[7]})
	l := common.BytesToUint32([4]byte{data[8], data[9], data[10], data[11]})
	if len(data[12:]) != int(l) {
		return nil, common.Errorf("Invalid data: %V", data)
	}
	data = data[12:]
	return newJob(common.RES, datatype, data), nil
}
Example #4
0
// inputing loop
func (a *agent) inLoop() {
	defer func() {
		if r := recover(); r != nil {
			a.worker.err(common.Errorf("Exiting: %s", r))
		}
		close(a.in)
		close(a.out)
		a.worker.removeAgent(a)
	}()
	for a.worker.running {
		a.WriteJob(newJob(common.REQ, common.PRE_SLEEP, nil))
	RESTART:
		// got noop msg and in queue is zero, grab job
		rel, err := a.read()
		if err != nil {
			if err == common.ErrConnection {
				for i := 0; i < 3 && a.worker.running; i++ {
					if conn, err := net.Dial(common.NETWORK, a.addr); err != nil {
						a.worker.err(common.Errorf("Reconnection: %d faild", i))
						continue
					} else {
						a.conn = conn
						goto RESTART
					}
				}
				a.worker.err(err)
				break
			}
			a.worker.err(err)
			continue
		}
		job, err := decodeJob(rel)
		if err != nil {
			a.worker.err(err)
			continue
		}
		switch job.DataType {
		case common.NOOP:
			a.WriteJob(newJob(common.REQ, common.GRAB_JOB_UNIQ, nil))
		case common.ERROR, common.ECHO_RES, common.JOB_ASSIGN_UNIQ, common.JOB_ASSIGN:
			if a.worker.running {
				if a.worker.limit != nil {
					a.worker.limit <- true
				}
				job.agent = a
				a.worker.in <- job
			}
		}
	}
}
Example #5
0
// Execute the job. And send back the result.
func (worker *Worker) exec(job *Job) (err error) {
	defer func() {
		if r := recover(); r != nil {
			if e, ok := r.(error); ok {
				err = e
			} else {
				err = common.ErrUnknown
			}
		}
	}()
	if worker.limit != nil {
		<-worker.limit
		defer func() {
			worker.limit <- true
		}()
	}
	var limit int
	if job.DataType == common.JOB_ASSIGN {
		limit = 3
	} else {
		limit = 4
	}
	jobdata := bytes.SplitN(job.Data, []byte{'\x00'}, limit)
	job.Handle = string(jobdata[0])
	funcname := string(jobdata[1])
	if job.DataType == common.JOB_ASSIGN {
		job.Data = jobdata[2]
	} else {
		job.UniqueId = string(jobdata[2])
		job.Data = jobdata[3]
	}
	f, ok := worker.funcs[funcname]
	if !ok {
		return common.Errorf("The function does not exist: %s", funcname)
	}
	var r *result
	if f.timeout == 0 {
		d, e := f.f(job)
		r = &result{data: d, err: e}
	} else {
		r = execTimeout(f.f, job, time.Duration(f.timeout)*time.Second)
	}
	var datatype uint32
	if r.err == nil {
		datatype = common.WORK_COMPLETE
	} else {
		if r.data == nil {
			datatype = common.WORK_FAIL
		} else {
			datatype = common.WORK_EXCEPTION
		}
		err = r.err
	}

	job.magicCode = common.REQ
	job.DataType = datatype
	job.Data = r.data
	job.agent.WriteJob(job)
	return
}
Example #6
0
// Internal read
func (a *agent) read() (data []byte, err error) {
BEGIN:
	inlen := len(a.in)
	if inlen > 0 {
		// in queue is not empty
		for i := 0; i < inlen; i++ {
			data = append(data, <-a.in...)
		}
	} else {
		for {
			buf := make([]byte, common.BUFFER_SIZE)
			var n int
			if n, err = a.conn.Read(buf); err != nil {
				if err == io.EOF && n == 0 {
					if data == nil {
						err = common.ErrConnection
						return
					}
					break
				}
				return
			}
			data = append(data, buf[0:n]...)
			if n < common.BUFFER_SIZE {
				break
			}
		}
	}
	// split package
	tl := len(data)
	if tl < 12 { // too few data to unpack, read more
		goto BEGIN
	}
	start := 0
	for i := 0; i < tl-11; i++ {
		if start+12 > tl { // too few data to unpack, read more
			goto BEGIN
		}
		if string(data[start:start+4]) == common.RES_STR {
			l := int(common.BytesToUint32([4]byte{data[start+8],
				data[start+9], data[start+10], data[start+11]}))
			total := l + 12
			if total == tl { // data is what we want
				return
			} else if total < tl { // data[:total] is what we want, data[total:] is the more
				a.in <- data[total:]
				data = data[:total]
				return
			} else { // ops! It won't be possible.
				goto BEGIN
			}
		} else { // flag was not found, move to next step
			start++
		}
	}
	goto BEGIN
	return nil, common.Errorf("Invalid data: %V", data)
}
Example #7
0
// Remove a function.
// Tell job servers 'I can not do this now' at the same time.
func (worker *Worker) RemoveFunc(funcname string) (err error) {
	if _, ok := worker.funcs[funcname]; !ok {
		return common.Errorf("The function does not exist: %s", funcname)
	}
	delete(worker.funcs, funcname)
	if worker.running {
		worker.removeFunc(funcname)
	}
	return
}
Example #8
0
// Add a function.
// Plz added job servers first, then functions.
// The API will tell every connected job server that 'I can do this'
func (worker *Worker) AddFunc(funcname string,
	f JobFunc, timeout uint32) (err error) {
	if _, ok := worker.funcs[funcname]; ok {
		return common.Errorf("The function already exists: %s", funcname)
	}
	worker.funcs[funcname] = &jobFunc{f: f, timeout: timeout}

	if worker.running {
		worker.addFunc(funcname, timeout)
	}
	return
}
Example #9
0
// status handler
func (client *Client) handleStatus(job *Job) {
	data := bytes.SplitN(job.Data, []byte{'\x00'}, 5)
	if len(data) != 5 {
		client.err(common.Errorf("Invalid data: %V", job.Data))
		return
	}
	status := &Status{}
	status.Handle = string(data[0])
	status.Known = (data[1][0] == '1')
	status.Running = (data[2][0] == '1')
	var err error
	status.Numerator, err = strconv.ParseUint(string(data[3][0]), 10, 0)
	if err != nil {
		client.err(common.Errorf("Invalid handle: %s", data[3][0]))
		return
	}
	status.Denominator, err = strconv.ParseUint(string(data[4][0]), 10, 0)
	if err != nil {
		client.err(common.Errorf("Invalid handle: %s", data[4][0]))
		return
	}
	client.status <- status
}
Example #10
0
// status handler
func (client *Client) handleStatus(job *Job) {
	if client.StatusHandler != nil {
		data := bytes.SplitN(job.Data, []byte{'\x00'}, 5)
		if len(data) != 5 {
			client.err(common.Errorf("Invalid data: %V", job.Data))
			return
		}
		handle := string(data[0])
		known := (data[1][0] == '1')
		running := (data[2][0] == '1')
		numerator, err := strconv.ParseUint(string(data[3][0]), 10, 0)
		if err != nil {
			client.err(common.Errorf("Invalid handle: %s", data[3][0]))
			return
		}
		denominator, err := strconv.ParseUint(string(data[4][0]), 10, 0)
		if err != nil {
			client.err(common.Errorf("Invalid handle: %s", data[4][0]))
			return
		}
		client.StatusHandler(handle, known, running, numerator, denominator)
	}
}
Example #11
0
// inner read
func (client *Client) read() (data []byte, err error) {
	if len(client.in) > 0 {
		// incoming queue is not empty
		data = <-client.in
	} else {
		// empty queue, read data from socket
		for {
			buf := make([]byte, common.BUFFER_SIZE)
			var n int
			if n, err = client.conn.Read(buf); err != nil {
				if err == io.EOF && n == 0 {
					if data == nil {
						err = common.ErrConnection
						return
					}
					break
				}
				return
			}
			data = append(data, buf[0:n]...)
			if n < common.BUFFER_SIZE {
				break
			}
		}
	}
	// split package
	tl := len(data)
	start, end := 0, 4
	for i := 0; i < tl; i++ {
		if string(data[start:end]) == common.RES_STR {
			l := int(common.BytesToUint32([4]byte{data[start+8], data[start+9], data[start+10], data[start+11]}))
			total := l + 12
			if total == tl {
				return
			} else {
				client.in <- data[total:]
				data = data[:total]
				return
			}
		} else {
			start++
			end++
		}
	}
	return nil, common.Errorf("Invalid data: %V", data)
}
Example #12
0
// Extract the job's result.
func (job *Job) Result() (data []byte, err error) {
	switch job.DataType {
	case common.WORK_FAIL:
		job.Handle = string(job.Data)
		return nil, common.ErrWorkFail
	case common.WORK_EXCEPTION:
		err = common.ErrWorkException
		fallthrough
	case common.WORK_COMPLETE:
		s := bytes.SplitN(job.Data, []byte{'\x00'}, 2)
		if len(s) != 2 {
			return nil, common.Errorf("Invalid data: %V", job.Data)
		}
		job.Handle = string(s[0])
		data = s[1]
	default:
		err = common.ErrDataType
	}
	return
}
Example #13
0
// Execute the job. And send back the result.
func (worker *Worker) exec(job *Job) (err error) {
	defer func() {
		if r := recover(); r != nil {
			if e, ok := r.(error); ok {
				err = e
			} else {
				err = common.ErrUnknown
			}
		}
	}()
	f, ok := worker.funcs[job.Fn]
	if !ok {
		return common.Errorf("The function does not exist: %s", job.Fn)
	}
	var r *result
	if f.timeout == 0 {
		d, e := f.f(job)
		r = &result{data: d, err: e}
	} else {
		r = execTimeout(f.f, job, time.Duration(f.timeout)*time.Second)
	}
	var datatype uint32
	if r.err == nil {
		datatype = common.WORK_COMPLETE
	} else {
		if r.data == nil {
			datatype = common.WORK_FAIL
		} else {
			datatype = common.WORK_EXCEPTION
		}
		err = r.err
	}

	job.magicCode = common.REQ
	job.DataType = datatype
	job.Data = r.data
	if worker.running {
		job.agent.WriteJob(job)
	}
	return
}