virtual ssize_t pwritev2_mutable()

in fs/aligned-file.cpp [192:265]


        virtual ssize_t pwritev2_mutable(struct iovec *iov, int iovcnt, off_t offset, int flags) override {
            struct iovec tmpiovec[MAX_TMP_IOVEC_SIZE];
            iovector_view view(tmpiovec, MAX_TMP_IOVEC_SIZE);
            iovector_view buf(iov, iovcnt);
            auto count = buf.sum();
            if (count == 0) return 0;
            range_split_power2 rs(offset, count, m_alignment);
            if (rs.is_aligned() && (!m_align_memory || iov_align_check(buf)))
                return m_file->pwritev2_mutable(iov, iovcnt, offset, flags);

            struct stat stat;
            m_file->fstat(&stat);
            ssize_t filesize = stat.st_size;
            auto suppose_filesize = (offset + (ssize_t)count) > filesize ? offset + count: filesize;
            IOVector wbuf(m_allocator);
            auto ret = wbuf.push_back(rs.aligned_length());
            if (ret < rs.aligned_length())
                LOG_ERROR_RETURN(0, -1, "Failed to allocate memory");

            if (rs.begin_remainder > 0)
            {
                view.iovcnt = MAX_TMP_IOVEC_SIZE;
                ssize_t ret = wbuf.slice(m_alignment, 0, &view);
                assert(ret == m_alignment);
                ssize_t off = rs.aligned_begin_offset();
                ret = m_file->preadv2(view.iov, view.iovcnt, off, flags);
                if ((ret < 0) || ((off + ret < filesize) && (ret < (ssize_t)m_alignment)))
                    LOG_ERRNO_RETURN(0, -1, "failed to aligned [`]->preadv2(iov=`, iovcnt=`, offset=`, flags=`) and patch the first alignment block",
                                     m_file, view.iov, view.iovcnt, off, flags);
                if (ret < (ssize_t)m_alignment) {
                    view.extract_front(ret);
                    for (auto &p : view) {
                        memset(p.iov_base, 0, p.iov_len);
                    }
                }
            }
            if (!rs.small_note && rs.end_remainder > 0)
            {
                ssize_t off = rs.aligned_end_offset() - m_alignment; // this should never be negative
                if (filesize - off > (ssize_t)(rs.end_remainder)) {
                    // that means there is still parts of data after the rear end of pwrite block
                    view.iovcnt = MAX_TMP_IOVEC_SIZE;
                    ssize_t ret = wbuf.slice(m_alignment, wbuf.sum() - m_alignment, &view);
                    assert(ret == m_alignment);
                    ret = m_file->preadv2(view.iov, view.iovcnt, off, flags);
                    if (ret < 0)
                        LOG_ERRNO_RETURN(0, -1, "failed to aligned [`]->preadv2(ptr=`, count=`, offset=`, flags=`)",
                                         m_file, view.iov, view.iovcnt, off, flags);
                    if ((ret + off < filesize) && (ret < (ssize_t)m_alignment)) // cannot fetch all data of file, and cannot fillup aligned block
                        LOG_ERRNO_RETURN(0, -1, "aligned [`]->preadv2(ptr=`, count=`, offset=`, flags=`) partial read",
                                         m_file, view.iov, view.iovcnt, off, flags);
                }
            }
            view.iovcnt = MAX_TMP_IOVEC_SIZE;
            ret = wbuf.slice(count, rs.begin_remainder, &view);
            assert(ret == count);
            ret = view.memcpy_from(&buf, count);
            assert(ret == count);
            auto actual_write = m_file->pwritev2_mutable(wbuf.iovec(), wbuf.iovcnt(), rs.aligned_begin_offset(), flags);
            auto current_tail = rs.aligned_begin_offset() + actual_write;
            if ((ssize_t)current_tail < offset)
                LOG_ERRNO_RETURN(0, -1, "failed to pwritev2");
            if (suppose_filesize < current_tail) { // that means have written more than needs
                m_file->ftruncate(suppose_filesize);
                current_tail = suppose_filesize;
            } else { // means pwrite will not extend file

            }
            auto count_write = current_tail - offset;
            if (count_write > count)
                count_write = count;
            return count_write;

        }