예제 #1
0
func (w *WriteSeeker) Flush(buf []byte, final bool) (err error) {
	if w.session == nil || w.key == nil {
		return fmt.Errorf("trying to write into empty interface")
	}

	if w.local_offset == 0 {
		return nil
	}

	wch := new_write_channel()

	len64 := uint64(len(buf))

	if w.prepared {
		if (uint64(w.remote_offset)+len64 == w.total_size) || final {
			w.prepared = false
			C.session_write_commit(w.session.session,
				C.context_t(wch.on_result_context), C.context_t(wch.on_finish_context),
				w.key.key, C.uint64_t(w.remote_offset), C.uint64_t(w.total_size),
				(*C.char)(unsafe.Pointer(&buf[0])), C.uint64_t(len64))
		} else {
			C.session_write_plain(w.session.session,
				C.context_t(wch.on_result_context), C.context_t(wch.on_finish_context),
				w.key.key, C.uint64_t(w.remote_offset),
				(*C.char)(unsafe.Pointer(&buf[0])), C.uint64_t(len64))
		}
	} else {
		if uint64(w.remote_offset)+len64 == w.total_size || w.reserve_size == 0 {
			// the whole package fits this chunk, use common write
			C.session_write_data(w.session.session,
				C.context_t(wch.on_result_context), C.context_t(wch.on_finish_context),
				w.key.key, C.uint64_t(w.remote_offset),
				(*C.char)(unsafe.Pointer(&buf[0])), C.uint64_t(len64))
		} else {
			w.prepared = true
			C.session_write_prepare(w.session.session,
				C.context_t(wch.on_result_context), C.context_t(wch.on_finish_context),
				w.key.key, C.uint64_t(w.remote_offset), C.uint64_t(w.reserve_size),
				(*C.char)(unsafe.Pointer(&buf[0])), C.uint64_t(len64))
		}
	}

	w.remote_offset += int64(len64)

	have_good_write := false
	errors := make([]error, 0)
	for wr := range wch.response {
		err = wr.Error()
		if err != nil {
			errors = append(errors, err)
			continue
		}

		have_good_write = true
	}

	if have_good_write == false {
		return fmt.Errorf("write failed, remote_offset: %d, reserve_size: %d, total_size: %d, chunk_size: %d, errors: %v",
			w.remote_offset-int64(len64), w.reserve_size, w.total_size, len64, errors)
	}

	return nil
}
예제 #2
0
func (s *Session) WriteChunk(key string, input io.Reader, initial_offset, total_size uint64) <-chan Lookuper {
	responseCh := make(chan Lookuper, defaultVOLUME)
	onChunkContext := NextContext()
	onFinishContext := NextContext()
	chunk_context := NextContext()

	chunk := make([]byte, max_chunk_size, max_chunk_size)

	orig_total_size := total_size
	offset := initial_offset
	var n64 uint64

	onChunkResult := func(lookup *lookupResult) {
		if total_size == 0 {
			responseCh <- lookup
		}
	}

	var onChunkFinish func(err error)

	onChunkFinish = func(err error) {
		if err != nil {
			responseCh <- &lookupResult{err: err}
			close(responseCh)
			Pool.Delete(onChunkContext)
			Pool.Delete(onFinishContext)
			Pool.Delete(chunk_context)
			return
		}

		if total_size == 0 {
			close(responseCh)
			Pool.Delete(onChunkContext)
			Pool.Delete(onFinishContext)
			Pool.Delete(chunk_context)
			return
		}

		n, err := input.Read(chunk)
		if n <= 0 && err != nil {
			responseCh <- &lookupResult{err: err}
			close(responseCh)
			Pool.Delete(onChunkContext)
			Pool.Delete(onFinishContext)
			Pool.Delete(chunk_context)
			return
		}

		n64 = uint64(n)
		total_size -= n64
		offset += n64

		ekey, err := NewKey(key)
		if err != nil {
			responseCh <- &lookupResult{err: err}
			close(responseCh)
			Pool.Delete(onChunkContext)
			Pool.Delete(onFinishContext)
			Pool.Delete(chunk_context)
			return
		}
		defer ekey.Free()

		if total_size != 0 {
			C.session_write_plain(s.session,
				C.context_t(onChunkContext), C.context_t(onFinishContext),
				ekey.key, C.uint64_t(offset-n64),
				(*C.char)(unsafe.Pointer(&chunk[0])), C.uint64_t(n))
		} else {
			C.session_write_commit(s.session,
				C.context_t(onChunkContext), C.context_t(onFinishContext),
				ekey.key, C.uint64_t(offset-n64), C.uint64_t(offset),
				(*C.char)(unsafe.Pointer(&chunk[0])), C.uint64_t(n))
		}
	}

	rest := total_size
	if rest > max_chunk_size {
		rest = max_chunk_size
	}

	n, err := input.Read(chunk)
	if err != nil {
		responseCh <- &lookupResult{err: err}
		close(responseCh)
		return responseCh
	}

	if n == 0 {
		responseCh <- &lookupResult{
			err: &DnetError{
				Code:  -22,
				Flags: 0,
				Message: fmt.Sprintf("Invalid zero-length write: current-offset: %d/%d, rest-size: %d/%d",
					initial_offset, offset, total_size, orig_total_size),
			},
		}
	}

	n64 = uint64(n)
	total_size -= n64
	offset += n64

	ekey, err := NewKey(key)
	if err != nil {
		responseCh <- &lookupResult{err: err}
		close(responseCh)
		return responseCh
	}
	defer ekey.Free()

	Pool.Store(onChunkContext, onChunkResult)
	Pool.Store(onFinishContext, onChunkFinish)
	Pool.Store(chunk_context, chunk)

	C.session_write_prepare(s.session,
		C.context_t(onChunkContext), C.context_t(onFinishContext),
		ekey.key, C.uint64_t(offset-n64), C.uint64_t(total_size+n64),
		(*C.char)(unsafe.Pointer(&chunk[0])), C.uint64_t(n))
	return responseCh
}