ssize_t FdEntity::WriteMixMultipart()

in src/fdcache_entity.cpp [2071:2145]


ssize_t FdEntity::WriteMixMultipart(PseudoFdInfo* pseudo_obj, const char* bytes, off_t start, size_t size)
{
    S3FS_PRN_DBG("[path=%s][pseudo_fd=%d][physical_fd=%d][offset=%lld][size=%zu]", path.c_str(), (pseudo_obj ? pseudo_obj->GetPseudoFd() : -1), physical_fd, static_cast<long long int>(start), size);

    if(-1 == physical_fd || !pseudo_obj){
        S3FS_PRN_ERR("pseudo_fd(%d) to physical_fd(%d) for path(%s) is not opened or not writable", (pseudo_obj ? pseudo_obj->GetPseudoFd() : -1), physical_fd, path.c_str());
        return -EBADF;
    }

    int result;

    if(!pseudo_obj->IsUploading()){
        // check disk space
        off_t restsize = pagelist.GetTotalUnloadedPageSize(0, start, MIN_MULTIPART_SIZE) + size;
        if(ReserveDiskSpace(restsize)){
            // enough disk space
            FdManager::FreeReservedDiskSpace(restsize);
        }else{
            // no enough disk space
            if((start + static_cast<off_t>(size)) <= S3fsCurl::GetMultipartSize()){
                S3FS_PRN_WARN("Not enough local storage to cache write request till multipart upload can start: [path=%s][physical_fd=%d][offset=%lld][size=%zu]", path.c_str(), physical_fd, static_cast<long long int>(start), size);
                return -ENOSPC;   // No space left on device
            }
            if(0 != (result = NoCachePreMultipartPost(pseudo_obj))){
                S3FS_PRN_ERR("failed to switch multipart uploading with no cache(errno=%d)", result);
                return result;
            }
            // start multipart uploading
            if(0 != (result = NoCacheLoadAndPost(pseudo_obj, 0, start))){
                S3FS_PRN_ERR("failed to load uninitialized area and multipart uploading it(errno=%d)", result);
                return result;
            }

            pseudo_obj->ClearUntreated();
        }
    }else{
        // already start multipart uploading
    }

    // Writing
    ssize_t wsize;
    if(-1 == (wsize = pwrite(physical_fd, bytes, size, start))){
        S3FS_PRN_ERR("pwrite failed. errno(%d)", errno);
        return -errno;
    }
    if(0 < wsize){
        pagelist.SetPageLoadedStatus(start, wsize, PageList::PAGE_LOAD_MODIFIED);
        pseudo_obj->AddUntreated(start, wsize);
    }

    // check multipart uploading
    if(pseudo_obj->IsUploading()){
        // get last untreated part(maximum size is multipart size)
        off_t untreated_start = 0;
        off_t untreated_size  = 0;
        if(pseudo_obj->GetLastUntreated(untreated_start, untreated_size, S3fsCurl::GetMultipartSize())){
            // when multipart max size is reached
            if(0 != (result = NoCacheMultipartPost(pseudo_obj, physical_fd, untreated_start, untreated_size))){
                S3FS_PRN_ERR("failed to multipart post(start=%lld, size=%lld) for file(physical_fd=%d).", static_cast<long long int>(untreated_start), static_cast<long long int>(untreated_size), physical_fd);
                return result;
            }

            // [NOTE]
            // truncate file to zero and set length to part offset + size
            // after this, file length is (offset + size), but file does not use any disk space.
            //
            if(-1 == ftruncate(physical_fd, 0) || -1 == ftruncate(physical_fd, (untreated_start + untreated_size))){
                S3FS_PRN_ERR("failed to truncate file(physical_fd=%d).", physical_fd);
                return -errno;
            }
            pseudo_obj->ClearUntreated(untreated_start, untreated_size);
        }
    }
    return wsize;
}