/*
 * nasd_cheops_mgr_qos.c
 *
 * Qos allocation
 */
/*
 * Copyright (c) 1996,1997,1998,1999 Carnegie Mellon University.
 * All rights reserved.
 *
 * Author: Khalil Amiri, CMU SCS/ECE, July 18 1997
 */
/*
 * Copyright (c) of Carnegie Mellon University, 1996,1997,1998,1999.
 *
 * Permission to reproduce, use, and prepare derivative works of
 * this software for internal use is granted provided the copyright
 * and "No Warranty" statements are included with all reproductions
 * and derivative works. This software may also be redistributed
 * without charge provided that the copyright and "No Warranty"
 * statements are included in all redistributions.
 *
 * NO WARRANTY. THIS SOFTWARE IS FURNISHED ON AN "AS IS" BASIS.
 * CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED AS TO THE MATTER INCLUDING, BUT NOT LIMITED
 * TO: WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY
 * OF RESULTS OR RESULTS OBTAINED FROM USE OF THIS SOFTWARE. CARNEGIE
 * MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT
 * TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
 */


#include <nasd/nasd_options.h>
#include <nasd/nasd_types.h>
#include <nasd/nasd_mem.h>
#include <nasd/nasd_threadstuff.h>
#include <nasd/nasd_cheops_types.h>
#include <nasd/nasd_cheops_common.h>
#include <nasd/nasd_cheops_mgr_common.h>
#include <nasd/nasd_cheops_mgr_internal.h>

/* map a Qos requirement structure onto a layout                       */
/* algorithms projects the requirements onto a set of classes, one for */
/* access size, one for throughput/bandwidth, one for reliability, and */
/* for access pattern (write ratio for now)                            */
/* The list of classes form a tuple which is used to index a table     */
/* storing the best layout for each tuple of requirement classes.      */

int Nasd_cheops_layouts[4][4][4];

#define CUTOFF_SMALL_IO        16
#define CUTOFF_VERY_LARGE_IO   512
#define CUTOFF_LOW_WRITES      0.2
#define CUTOFF_HIGH_WRITES     0.5
 
#define NASD_CHEOPS_STRIPE_WIDTH 8      /* the default stripe width */
/* XXX In init.c Khalil had this as 64*1024, but here he has it as
   128.  WTF.  Changing it for now to 64.  SNL */
#define NASD_CHEOPS_STRIPE_SIZE 64*1024  /* the default stripe unit size */

/* debugging */
#define NASD_CHEOPS_QOS_DEBUG 0

int 
nasd_cheops_bs_req_to_layout(
  nasd_cheops_qos_req_t         *qr,
  nasd_cheops_bs_layout_t       *lp)
{
  nasd_cheops_ac_pattern_class_t    ac_pattern_class;
  nasd_cheops_wratio_class_t        wratio_class;
  nasd_cheops_reli_class_t          reli_class;

  /* classify the write ratio */
#if 0
  if (qr->write_ratio < CUTOFF_LOW_WRITES)
    wratio_class = _NASD_CHEOPS_QOS_MOSTLY_READ;
  else if (qr->write_ratio > CUTOFF_HIGH_WRITES)
    wratio_class = _NASD_CHEOPS_QOS_MOSTLY_WRITE;
  else
    wratio_class =  _NASD_CHEOPS_QOS_READWRITE;
#else
  /* XXX doubles are not supported in RPC stuff */
  /* find some other representation */
  NASD_PANIC();
#endif
	
  /* classify the bandwidth/throughput class */
  if ( (qr->parallelism==1) && (qr->typ_access_size<CUTOFF_SMALL_IO) )
    ac_pattern_class = NASD_CHEOPS_QOS_ONE_SMALL_IO;
  else if ( (qr->parallelism>1) && (qr->typ_access_size<CUTOFF_SMALL_IO) )
    ac_pattern_class = NASD_CHEOPS_QOS_MANY_SMALL_IOS;
  else if ( (qr->parallelism==1) )
    ac_pattern_class = NASD_CHEOPS_QOS_ONE_LARGE_IO;
  else
    ac_pattern_class = NASD_CHEOPS_QOS_MANY_LARGE_IOS;
	         
  reli_class = qr->reli_class;

  lp->raid_level =
    Nasd_cheops_layouts[ac_pattern_class][wratio_class][reli_class];
  lp->stripe_unit_size = NASD_CHEOPS_STRIPE_SIZE;
  if (lp->stripe_unit_size < qr->min_su_size)
    lp->stripe_unit_size = qr->min_su_size;
  lp->num_data_col = NASD_CHEOPS_STRIPE_WIDTH; 
#if NASD_CHEOPS_QOS_DEBUG > 0	
  (cheops_Msg "inside bs_req to layout, su=%d, gsize=%d \n",
   lp->stripe_unit_size, lp->num_data_col);
#endif

  if (NumDrives == 1)
    lp->raid_level = RAID0;
  else if (NumDrives == 2) {
    if (lp->raid_level == RAID5)
      lp->raid_level = RAID1;
  } 

  switch(lp->raid_level) {
  case RAID0:
    lp->num_col = lp->num_data_col;
    break;
  case RAID1: 
    lp->num_col = 2*lp->num_data_col;
    if (lp->num_col > NumDrives) {
      lp->num_col = (NumDrives/2) *2;
      lp->num_data_col = NumDrives/2;
    }
    break;
  case RAID5:
    lp->num_col = lp->num_data_col + 1;
    if (lp->num_col > NumDrives) {
      lp->num_col = NumDrives;
      lp->num_data_col = NumDrives-1;
    }
    break;
  default:
    NASD_ASSERT(0);
  }
       
  return 0;
};

int
nasd_cheops_bs_qos_init(
  void)
{

  /* object requires low reliability: 
     . map onto a RAID level 0
	*/

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_ONE_SMALL_IO]
    [NASD_CHEOPS_QOS_MOSTLY_READ]
    [NASD_CHEOPS_QOS_LOW_RELI] = RAID0;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_MANY_SMALL_IOS]
    [NASD_CHEOPS_QOS_MOSTLY_READ]
    [NASD_CHEOPS_QOS_LOW_RELI] = RAID0;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_ONE_LARGE_IO]
    [NASD_CHEOPS_QOS_MOSTLY_READ]
    [NASD_CHEOPS_QOS_LOW_RELI] = RAID0;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_MANY_LARGE_IOS]
    [NASD_CHEOPS_QOS_MOSTLY_READ]
    [NASD_CHEOPS_QOS_LOW_RELI] = RAID0;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_ONE_SMALL_IO]
    [NASD_CHEOPS_QOS_MOSTLY_WRITE]
    [NASD_CHEOPS_QOS_LOW_RELI] = RAID0;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_MANY_SMALL_IOS]
    [NASD_CHEOPS_QOS_MOSTLY_WRITE]
    [NASD_CHEOPS_QOS_LOW_RELI] = RAID0;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_ONE_LARGE_IO]
    [NASD_CHEOPS_QOS_MOSTLY_WRITE]
    [NASD_CHEOPS_QOS_LOW_RELI] = RAID0;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_MANY_LARGE_IOS]
    [NASD_CHEOPS_QOS_MOSTLY_WRITE]
    [NASD_CHEOPS_QOS_LOW_RELI] = RAID0;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_ONE_SMALL_IO]
    [NASD_CHEOPS_QOS_READWRITE]
    [NASD_CHEOPS_QOS_LOW_RELI] = RAID0;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_MANY_SMALL_IOS]
    [NASD_CHEOPS_QOS_READWRITE]
    [NASD_CHEOPS_QOS_LOW_RELI] = RAID0;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_ONE_LARGE_IO]
    [NASD_CHEOPS_QOS_READWRITE]
    [NASD_CHEOPS_QOS_LOW_RELI] = RAID0;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_MANY_LARGE_IOS]
    [NASD_CHEOPS_QOS_READWRITE]
    [NASD_CHEOPS_QOS_LOW_RELI] = RAID0;

  /* object requires medium reliability: 
     . map onto a RAID level 5 (if mostly read)
     . map onto a RAID level 1 (if mostly write)
  */

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_ONE_SMALL_IO]
    [NASD_CHEOPS_QOS_MOSTLY_READ]
    [NASD_CHEOPS_QOS_MOD_RELI] = RAID5;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_MANY_SMALL_IOS]
    [NASD_CHEOPS_QOS_MOSTLY_READ]
    [NASD_CHEOPS_QOS_MOD_RELI] = RAID5;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_ONE_LARGE_IO]
    [NASD_CHEOPS_QOS_MOSTLY_READ]
    [NASD_CHEOPS_QOS_MOD_RELI] = RAID5;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_MANY_LARGE_IOS]
    [NASD_CHEOPS_QOS_MOSTLY_READ]
    [NASD_CHEOPS_QOS_MOD_RELI] = RAID5;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_ONE_SMALL_IO]
    [NASD_CHEOPS_QOS_MOSTLY_WRITE]
    [NASD_CHEOPS_QOS_MOD_RELI] = RAID1;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_MANY_SMALL_IOS]
    [NASD_CHEOPS_QOS_MOSTLY_WRITE]
    [NASD_CHEOPS_QOS_MOD_RELI] = RAID1;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_ONE_LARGE_IO]
    [NASD_CHEOPS_QOS_MOSTLY_WRITE]
    [NASD_CHEOPS_QOS_MOD_RELI] = RAID5;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_MANY_LARGE_IOS]
    [NASD_CHEOPS_QOS_MOSTLY_WRITE]
    [NASD_CHEOPS_QOS_MOD_RELI] = RAID5;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_ONE_SMALL_IO]
    [NASD_CHEOPS_QOS_READWRITE]
    [NASD_CHEOPS_QOS_MOD_RELI] = RAID1;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_MANY_SMALL_IOS]
    [NASD_CHEOPS_QOS_READWRITE]
    [NASD_CHEOPS_QOS_MOD_RELI] = RAID1;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_ONE_LARGE_IO]
    [NASD_CHEOPS_QOS_READWRITE]
    [NASD_CHEOPS_QOS_MOD_RELI] = RAID5;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_MANY_LARGE_IOS]
    [NASD_CHEOPS_QOS_READWRITE]
    [NASD_CHEOPS_QOS_MOD_RELI] = RAID5;

  /* object requires high reliability: 
     . map onto a RAID level 1 
  */

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_ONE_SMALL_IO]
    [NASD_CHEOPS_QOS_MOSTLY_READ]
    [NASD_CHEOPS_QOS_HIGH_RELI] = RAID1;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_MANY_SMALL_IOS]
    [NASD_CHEOPS_QOS_MOSTLY_READ]
    [NASD_CHEOPS_QOS_HIGH_RELI] = RAID1;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_ONE_LARGE_IO]
    [NASD_CHEOPS_QOS_MOSTLY_READ]
    [NASD_CHEOPS_QOS_HIGH_RELI] = RAID1;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_MANY_LARGE_IOS]
    [NASD_CHEOPS_QOS_MOSTLY_READ]
    [NASD_CHEOPS_QOS_HIGH_RELI] = RAID1;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_ONE_SMALL_IO]
    [NASD_CHEOPS_QOS_MOSTLY_WRITE]
    [NASD_CHEOPS_QOS_HIGH_RELI] = RAID1;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_MANY_SMALL_IOS]
    [NASD_CHEOPS_QOS_MOSTLY_WRITE]
    [NASD_CHEOPS_QOS_HIGH_RELI] = RAID1;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_ONE_LARGE_IO]
    [NASD_CHEOPS_QOS_MOSTLY_WRITE]
    [NASD_CHEOPS_QOS_HIGH_RELI] = RAID1;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_MANY_LARGE_IOS]
    [NASD_CHEOPS_QOS_MOSTLY_WRITE]
    [NASD_CHEOPS_QOS_HIGH_RELI] = RAID1;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_ONE_SMALL_IO]
    [NASD_CHEOPS_QOS_READWRITE]
    [NASD_CHEOPS_QOS_HIGH_RELI] = RAID1;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_MANY_SMALL_IOS]
    [NASD_CHEOPS_QOS_READWRITE]
    [NASD_CHEOPS_QOS_HIGH_RELI] = RAID1;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_ONE_LARGE_IO]
    [NASD_CHEOPS_QOS_READWRITE]
    [NASD_CHEOPS_QOS_HIGH_RELI] = RAID1;

  Nasd_cheops_layouts[NASD_CHEOPS_QOS_MANY_LARGE_IOS]
    [NASD_CHEOPS_QOS_READWRITE]
    [NASD_CHEOPS_QOS_HIGH_RELI] = RAID1;

  return 0;
}

/* Local Variables:  */
/* indent-tabs-mode: nil */
/* tab-width: 2 */
/* End: */
