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 }
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 }