class PageReadWriteManagerImpl implements PageReadWriteManager {
    /** */
    private final GridKernalContext ctx;

    /** */
    @GridToStringExclude
    protected final PageStoreCollection pageStores;

    /** */
    @SuppressWarnings("unused")
    private final String name;

    /**
     * @param ctx Kernal context.
     * @param pageStores Page stores.
     */
    public PageReadWriteManagerImpl(
        GridKernalContext ctx,
        PageStoreCollection pageStores,
        String name
    ) {
        this.ctx = ctx;
        this.pageStores = pageStores;
        this.name = name;
    }

    /** {@inheritDoc} */
    @Override public void read(int grpId, long pageId, ByteBuffer pageBuf, boolean keepCrc) throws IgniteCheckedException {
        PageStore store = pageStores.getStore(grpId, PageIdUtils.partId(pageId));

        try {
            store.read(pageId, pageBuf, keepCrc);

            ctx.compress().decompressPage(pageBuf, store.getPageSize());
        }
        catch (StorageException e) {
            ctx.failure().process(new FailureContext(FailureType.CRITICAL_ERROR, e));

            throw e;
        }
    }

    /** {@inheritDoc} */
    @Override public PageStore write(
        int grpId,
        long pageId,
        ByteBuffer pageBuf,
        int tag,
        boolean calculateCrc
    ) throws IgniteCheckedException {<FILL_FUNCTION_BODY>}

    /** {@inheritDoc} */
    @Override public long allocatePage(int grpId, int partId, byte flags) throws IgniteCheckedException {
        assert partId <= MAX_PARTITION_ID || partId == INDEX_PARTITION;

        PageStore store = pageStores.getStore(grpId, partId);

        try {
            long pageIdx = store.allocatePage();

            return PageIdUtils.pageId(partId, flags, (int)pageIdx);
        }
        catch (StorageException e) {
            ctx.failure().process(new FailureContext(FailureType.CRITICAL_ERROR, e));

            throw e;
        }
    }

    /** {@inheritDoc} */
    @Override public String toString() {
        return S.toString(PageReadWriteManagerImpl.class, this);
    }
}

        int partId = PageIdUtils.partId(pageId);

        PageStore store = pageStores.getStore(grpId, partId);

        try {
            int pageSize = store.getPageSize();
            int compressedPageSize = pageSize;

            CacheGroupContext grpCtx = ctx.cache().cacheGroup(grpId);
            if (grpCtx != null) {
                assert pageBuf.position() == 0 && pageBuf.limit() == pageSize : pageBuf;

                ByteBuffer compressedPageBuf = grpCtx.compressionHandler().compressPage(pageBuf, store);

                if (compressedPageBuf != pageBuf) {
                    compressedPageSize = PageIO.getCompressedSize(compressedPageBuf);

                    if (!calculateCrc) {
                        calculateCrc = true;
                        PageIO.setCrc(compressedPageBuf, 0); // It will be recalculated over compressed data further.
                    }

                    PageIO.setCrc(pageBuf, 0); // It is expected to be reset to 0 after each write.
                    pageBuf = compressedPageBuf;
                }
            }

            store.write(pageId, pageBuf, tag, calculateCrc);

            if (pageSize > compressedPageSize)
                store.punchHole(pageId, compressedPageSize); // TODO maybe add async punch mode?
        }
        catch (StorageException e) {
            ctx.failure().process(new FailureContext(FailureType.CRITICAL_ERROR, e));

            throw e;
        }

        return store;
    
<no_super_class>