/*
 * Copyright (c) 2020 Red Hat, Inc.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA. 
 *
 * $Id: //eng/uds-releases/jasper/src/uds/indexLayout.h#13 $
 */

#ifndef INDEX_LAYOUT_H
#define INDEX_LAYOUT_H

#include "buffer.h"
#include "indexState.h"
#include "indexVersion.h"
#include "ioFactory.h"
#include "uds.h"

typedef struct indexLayout IndexLayout;

/**
 * Construct an index layout.  This is a platform specific function that uses
 * the name string, a flag that indicates old vs. new indices, and a
 * UDSConfiguration (for new indices) to make an IOFactory and invoke
 * makeIndexLayoutFromFactory.
 *
 * @param name       String naming the index.  Each platform will use its own
 *                   conventions to interpret the string, but in general it is
 *                   a space-separated sequence of param=value settings.  For
 *                   backward compatibility a string without an equals is
 *                   treated as a platform-specific default parameter value.
 * @param newLayout  Whether this is a new layout.
 * @param config     The UdsConfiguration required for a new layout.
 * @param layoutPtr  Where to store the new index layout
 *
 * @return UDS_SUCCESS or an error code.
 **/
int makeIndexLayout(const char              *name,
                    bool                     newLayout,
                    const UdsConfiguration   config,
                    IndexLayout            **layoutPtr)
  __attribute__((warn_unused_result));

/**
 * Construct an index layout using an IOFactory.  This method is common to all
 * platforms.
 *
 * @param factory    The IOFactory for the block storage containing the index.
 * @param offset     The offset of the start of the index within the block
 *                   storage address space.
 * @param namedSize  The size in bytes of the space within the block storage
 *                   address space, as specified in the name string.
 * @param newLayout  Whether this is a new layout.
 * @param config     The UdsConfiguration required for a new layout.
 * @param layoutPtr  Where to store the new index layout
 *
 * @return UDS_SUCCESS or an error code.
 **/
int makeIndexLayoutFromFactory(IOFactory               *factory,
                               off_t                    offset,
                               uint64_t                 namedSize,
                               bool                     newLayout,
                               const UdsConfiguration   config,
                               IndexLayout            **layoutPtr)
  __attribute__((warn_unused_result));

/**
 * Decrement the use count of an index layout.  If the count goes to zero, free
 * the index layout.
 *
 * @param layoutPtr  Where the layout is being stored.  Always reset to NULL.
 **/
void putIndexLayout(IndexLayout **layoutPtr);

/*****************************************************************************/
int cancelIndexSave(IndexLayout *layout, unsigned int saveSlot)
  __attribute__((warn_unused_result));

/*****************************************************************************/
int commitIndexSave(IndexLayout *layout, unsigned int saveSlot)
  __attribute__((warn_unused_result));

/*****************************************************************************/
int discardIndexSaves(IndexLayout *layout, bool all)
  __attribute__((warn_unused_result));

/**
 * Find the latest index save slot.
 *
 * @param [in]  layout          The single file layout.
 * @param [out] numZonesPtr     Where to store the actual number of zones
 *                                that were saved.
 * @param [out] slotPtr         Where to store the slot number we found.
 *
 * @return UDS_SUCCESS or an error code.
 **/
int findLatestIndexSaveSlot(IndexLayout  *layout,
                            unsigned int *numZonesPtr,
                            unsigned int *slotPtr)
  __attribute__((warn_unused_result));

/**
 * Get another reference to an index layout, incrementing it's use count.
 *
 * @param layout     The index layout.
 * @param layoutPtr  Where the new layout pointer is being stored.
 **/
void getIndexLayout(IndexLayout *layout, IndexLayout **layoutPtr);

/**
 * Open a BufferedReader for a specified state, kind, and zone.
 *
 * @param layout     The index layout
 * @param slot       The save slot
 * @param kind       The kind if index save region to open.
 * @param zone       The zone number for the region.
 * @param readerPtr  Where to store the BufferedReader.
 *
 * @return UDS_SUCCESS or an error code.
 **/
int openIndexBufferedReader(IndexLayout     *layout,
                            unsigned int     slot,
                            RegionKind       kind,
                            unsigned int     zone,
                            BufferedReader **readerPtr)
  __attribute__((warn_unused_result));

/**
 * Open a BufferedWriter for a specified state, kind, and zone.
 *
 * @param layout     The index layout
 * @param slot       The save slot
 * @param kind       The kind if index save region to open.
 * @param zone       The zone number for the region.
 * @param writerPtr  Where to store the BufferedWriter.
 *
 * @return UDS_SUCCESS or an error code.
 **/
int openIndexBufferedWriter(IndexLayout     *layout,
                            unsigned int     slot,
                            RegionKind       kind,
                            unsigned int     zone,
                            BufferedWriter **writerPtr)
  __attribute__((warn_unused_result));

/**
 * Obtain the nonce to be used to store or validate the loading of volume index
 * pages.
 *
 * @param [in]  layout   The index layout.
 *
 * @return The nonce to use.
 **/
uint64_t getVolumeNonce(IndexLayout *layout)
  __attribute__((warn_unused_result));

#ifdef __KERNEL__
/**
 * Obtain a dm_bufio_client for the specified index volume.
 *
 * @param [in]  layout           The index layout.
 * @param [in]  blockSize        The size of a volume page
 * @param [in]  reservedBuffers  The count of reserved buffers
 * @param [out] clientPtr        Where to put the new dm_bufio_client
 *
 * @return UDS_SUCCESS or an error code.
 **/
int openVolumeBufio(IndexLayout             *layout,
                    size_t                   blockSize,
                    unsigned int             reservedBuffers,
                    struct dm_bufio_client **clientPtr)
  __attribute__((warn_unused_result));
#else
/**
 * Obtain an IORegion for the specified index volume.
 *
 * @param [in]  layout     The index layout.
 * @param [out] regionPtr  Where to put the new region.
 *
 * @return UDS_SUCCESS or an error code.
 **/
int openVolumeRegion(IndexLayout *layout, struct ioRegion **regionPtr)
  __attribute__((warn_unused_result));
#endif

/**
 * Read the index configuration, and verify that it matches the given
 * configuration.
 *
 * @param layout  the generic index layout
 * @param config  the index configuration
 *
 * @return UDS_SUCCESS or an error code
 **/
int verifyIndexConfig(IndexLayout *layout, UdsConfiguration config)
  __attribute__((warn_unused_result));

/**
 * Determine which index save slot to use for a new index save.
 *
 * Also allocates the masterIndex regions and, if needed, the openChapter
 * region.
 *
 * @param [in]  layout          The index layout.
 * @param [in]  numZones        Actual number of zones currently in use.
 * @param [in]  saveType        The index save type.
 * @param [out] saveSlotPtr     Where to store the save slot number.
 *
 * @return UDS_SUCCESS or an error code
 **/
int setupIndexSaveSlot(IndexLayout   *layout,
                       unsigned int   numZones,
                       IndexSaveType  saveType,
                       unsigned int  *saveSlotPtr)
  __attribute__((warn_unused_result));

/**
 * Write the index configuration.
 *
 * @param layout  the generic index layout
 * @param config  the index configuration to write
 *
 * @return UDS_SUCCESS or an error code
 **/
int writeIndexConfig(IndexLayout *layout, UdsConfiguration config)
  __attribute__((warn_unused_result));

/**
 * Get the index state buffer
 *
 * @param layout  the index layout
 * @param slot    the save slot
 *
 * @return UDS_SUCCESS or an error code
 **/
Buffer *getIndexStateBuffer(IndexLayout *layout, unsigned int slot)
  __attribute__((warn_unused_result));

/**
 * Get the index version parameters.
 *
 * @param layout  the index layout
 *
 * @return the index version parameters.
 **/
const struct index_version *getIndexVersion(IndexLayout *layout)
  __attribute__((warn_unused_result));

#endif // INDEX_LAYOUT_H
