[prev in list] [next in list] [prev in thread] [next in thread] 

List:       gfs-devel
Subject:    [gfs-devel] fcntl with GFS-4.1.1
From:       christophe_barbé <christophe.barbe () lineo ! fr>
Date:       2001-07-09 9:47:30
[Download RAW message or body]

Hi,

I've written a little program which is intended to test distributed
file-systems. It doesn't evaluate performances but try to test the
reliability of concurrent read/write accesses.

It currently tests flock and fcntl locking methods, mmaped files, and does
not test (yet, it's in my todo list) fork of locked files, partial file
locking.

The main idea of this test is to share a fifo and a filo in a file between
multiple file-system clients. A master (the first instance) manage a
control
table (at the beginning of the shared files) in which it distributes roles
to others clients (slaves). This roles distributions is done in a way that
(is intended to) guaranty that all combinations are tested.

So if you start 'dfstest -f' on a shared directory, and start 'dfstest -f
&' on the same machine and on others, you will see something like this : 

Master
... using flock instead of fcntl

filo level [----      ] = 177
fifo level [------   -] = 341

#01 : (f  ) pid 765 on C0n4.int2.lineo.fr in mode fifo+
#02 : (f  ) pid 523 on C0n5.int2.lineo.fr in mode filo+
#03 : (f  ) pid 766 on C0n4.int2.lineo.fr in mode filo+
#04 : (f  ) pid 524 on C0n5.int2.lineo.fr in mode fifo+
#05 :
#06 :
#07 :
#08 :
#09 :
#10 :

Various options are available (dfstest --help). 
-n suppress the sleep between each operation
-m the file is mmapped
-f use flock instead of fcntl

I've attached the source to this mail. It require curses and popt
libraries. And should compiled fine with 
> gcc -g -Wall dfstest.c -o dfstest -lpopt -lcurses

Feedback is welcome.

With the last GFS-4.1.1, if I try to use fcntl I get a oops.

Christophe

-- 
Christophe Barbé
Software Engineer - christophe.barbe@lineo.fr
Lineo France - Lineo High Availability Group
42-46, rue Médéric - 92110 Clichy - France
phone (33).1.41.40.02.12 - fax (33).1.41.40.02.01
http://www.lineo.com
["dfstest.c" (text/x-c)]

/*********************************************************************

               dfstest : Distributed FileSytem Test

                      Christophe Barbé
                        24, nov 2000
                        Lineo France


This program is written to check the ability for a filesystem
(specifically distributed) to manage concurency read/write on
a file.
The default locking method is a fcntl() call but with the -f
option the flock() call can be used.
Data in the shared file are accessed with a classic
lseek/read/write combination but with the -m option data could
be memory mapped.

The test procedure is the following :
1. cd to a shared directory (the first instance create
   a file in the current directory).
2. start a first instance of this program with the choosen options.
   This instance shoud become a master and display usefull informations.
3. On an another computer in the case of a distributed filesystem,
   Start a new instance in background (command followed by a &).
   By default the master options are used by each new slave.
	(note that if the fcntl locking method is missing, you need to use the
	-f option for each instance).
   In slave mode, nothing is displayed. You should be able to see the
   new slave on the informations displayed by the master.
4. Start up to 9 others slave distributed on all computers including
   the master one.

Regularly, the Master attributes a new jobs to each slave. The possible
jobs are sleep, add/remove to filo, add/remove to fifo. This jobs are
attibuted in a way that ensures that all possible combinations are
tested. The jobs are implemented to be simple but NOT error tolerant.
If the shared file is modified on the same time by more than one slave
this file should appear corrupted.
If a modification on this file is based on an old content (modification
repercution problem) the file should appear be corrupted.

If the test runs without slave lost, then the distributed filesystem
should be ok for the choosen options.

Not yet implemented, use of fork (& co), use of partial file locking.

For a list of available options, run this program with the --help option.

 *********************************************************************/

/*
 * This program require the popt and curses libraries
 * and could be compiled with the following command line
 * gcc -g dfstest.c -o dfstest -lpopt -lcurses
 */

#define _GCC_UNUSED_ __attribute__ ((unused))
static char *cvsid _GCC_UNUSED_ =
  "$Id: dfstest.c,v 1.2 2001/07/09 09:16:23 barbe Exp $";

/* #include <sys/types.h> */
/* #include <sys/stat.h> */
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/mman.h>
#include <popt.h>
#include <values.h>
#include <sys/file.h>
#include <string.h>
#include <curses.h>

static int no_sleep = 0;
static int verbose = 0;
static int use_flock = 0;
static int use_mmap = 0;
static int use_option = 0;

struct poptOption options[] = { POPT_AUTOHELP
    {"option", 'o', POPT_ARG_NONE, &use_option, 0, "ignore master option", NULL},
	{"flock", 'f', POPT_ARG_NONE, &use_flock, 0, "use flock instead of fcntl", NULL},
	{"mmap", 'm', POPT_ARG_NONE, &use_mmap, 0, "use mmap", NULL},
	{"no_sleep", 'n', POPT_ARG_NONE, &no_sleep, 0, "don't use (random) sleep", NULL},
	{"verbose", 'v', POPT_ARG_NONE, &verbose, 0, "verbose", NULL},
	{NULL, (char) 0, 0, NULL, 0, NULL, NULL}
};

#define FILENAME "dfstest.data"
#define NB_CLIENT_MAX 10

typedef enum
{ BYE, OFF, FILO_ADD, FILO_REM, FIFO_ADD, FIFO_REM }
slave_mode;
char *slave_mode_str[] = { "bye", "zzz", "filo+", "filo-", "fifo+", "fifo-" };
#define NB_SLAVE_MODE 5		/* don't count the "bye" mode */

/* --------------------------------------------------
   The following data structure declaration is used
   directly when the use_mmap option is set.
   Otherwise it's used to compute lseek argument
   to move in the file.
   -------------------------------------------------- */

typedef struct
{
  unsigned int use_flock:1;
  unsigned int use_mmap:1;
  unsigned int no_sleep:1;
  unsigned int unused:29;
}
INFO;

#define MAX_HOSTNAME_LENGTH 30
typedef struct
{
  INFO info;
  pid_t pid;
  char hostname[MAX_HOSTNAME_LENGTH + 1];
  slave_mode mode;
}
CLIENT;

static CLIENT client[NB_CLIENT_MAX + 1];

#define FILO_SIZE 500
typedef struct
{
  int next;
  unsigned int value[FILO_SIZE];
}
FILO;

#define FIFO_SIZE 500
typedef struct
{
  int start;
  int next;
  int level;
  unsigned int value[FIFO_SIZE];
}
FIFO;

#define MARKER 123
#define NB_CLIENT_MAX 10
typedef struct
{
  CLIENT client[NB_CLIENT_MAX + 1];
  int marker1;
  FILO filo;
  int marker2;
  FIFO fifo;
  int marker3;
}
DATA_STRUCT;

DATA_STRUCT *data;

static int fd;
static struct flock fl;

/* string used to display the FILO/FIFO usage */
static char filo_str[] = "[0123456789]";
static char fifo_str[] = "[0123456789]";

static int position = 0;	/* ... in the client table (0 means master) */
static int counter = 0;		/* ... of operations */

/* local functions prototype */
static void fatal(char *msg);
static void bye(int sig);

static void open_and_verify(void);
static void lock(void);
static void unlock(void);

static void master(void);
static void slave(void);

static void display_status(CLIENT * client_state, int filo_level,
			   int fifo_level);

static void lseek_to(void *what);
static void lseek_int(int offset, int whence);
static void read_int(int *value);
static void write_int(int *value);
static void map_file(void);
static void synchronize(void);
static void unmap_file(void);

static void init_client_table(void);
static void read_client_table(void);
static void write_client_table(void);
static void set_whoiam(void);
static void verify_whoiam(void);

static int check_markers(void);
static void verify_markers(void);

static void init_filo(void);
static int check_filo(void);
static void display_filo(int level);

static void get_filo_level(int *level);
static void get_filo_level_mapped(int *level);

static void add_to_filo_notmapped(void);
static void remove_to_filo_notmapped(void);
static void add_to_filo_mapped(void);
static void remove_to_filo_mapped(void);

typedef void MY_FCT(void);
MY_FCT *add_to_filo;
MY_FCT *remove_to_filo;

static void init_fifo(void);
static int check_fifo(void);
static void display_fifo(int start, int next, int nb);

static void get_fifo_level(int *start, int *next, int *level);
static void get_fifo_level_mapped(int *start, int *next, int *level);

static void add_to_fifo_notmapped(void);
static void remove_to_fifo_notmapped(void);
static void add_to_fifo_mapped(void);
static void remove_to_fifo_mapped(void);

MY_FCT *add_to_fifo;
MY_FCT *remove_to_fifo;

/* Internal signals for bye() */
#define SIG_MASTER _NSIG+1
#define SIG_TABLE_CORRUPTED _NSIG+2
#define SIG_FILO_CORRUPTED _NSIG+3
#define SIG_FIFO_CORRUPTED _NSIG+4
#define SIG_MARKER_CORRUPTED _NSIG+5

/*
 * Main function :
 * - parse options
 * - open file
 * - set filo/fifo manipulation functions
 * - become a master, a slave otherwise
 *
 */
int
main(int argc, const char **argv)
{
  int cr;
  poptContext poptcon;

  /* initialize random generation */
  srand((unsigned int) getpid());	/* another idea ? */

  /* parse command line option */
  poptcon = poptGetContext(FILENAME, argc, argv, options, 0);
  cr = poptGetNextOpt(poptcon);
  poptFreeContext(poptcon);

  /* if testfile doesn't exist or is corrupted, create a new one */
  open_and_verify();

  /* try to exit gracefully when possible after a CTRL-C or a sigTERM */
  (void) signal(SIGTERM, bye);
  (void) signal(SIGINT, bye);

  master();
  slave();

  /*   Here we return FAILURE because we should never reach this point
     master() or slave() are infinite loops exited only
     by catched signal
   */
  return (EXIT_FAILURE);
}

/*-------------------------------------------------------------------
   File operations
  -------------------------------------------------------------------*/

static void
open_and_verify(void)
{
  int flag = 0;
  int marker = MARKER;

  /* open file, if required create it */
  fd = open(FILENAME, O_RDWR);
  if (fd == -1) {
    fd = open(FILENAME, O_CREAT | O_RDWR, 0644);
    if (fd == -1)
      fatal("unable to open file");
    fprintf(stderr, "test file created!\n");

    flag = 1;			/* file should be initialized */
  }

  lock();

  /* if required, reinitialized the filo */
  if ((flag == 1) || check_markers() || check_filo() || check_fifo()) {
    fprintf(stderr, "test file initialized!\n");

    init_client_table();
    write_int(&marker);		// marker1
    init_filo();
    write_int(&marker);		// marker2
    init_fifo();
    write_int(&marker);		// marker3
  }

  unlock();

}

static void
lock(void)
{
  if (use_flock) {
    if (flock(fd, LOCK_EX) < 0)
      fatal("flock");
  }
  else {
    bzero(&fl, sizeof(fl));
    fl.l_type = F_WRLCK;
    if (fcntl(fd, F_SETLKW, &fl) < 0)
      fatal("fcntl");
  }
}

static void
unlock(void)
{
  if (use_flock) {
    if (flock(fd, LOCK_UN) < 0)
      fatal("flock");
  }
  else {
    bzero(&fl, sizeof(fl));
    fl.l_type = F_UNLCK;
    if (fcntl(fd, F_SETLKW, &fl) < 0)
      fatal("fcntl");
  }
}

/*-------------------------------------------------------------------
   Master
  -------------------------------------------------------------------*/

static void
master(void)
{
  int i = 0, w1, w2;
  int state = 0;
  int filo_level;
  int fifo_start, fifo_next, fifo_nb;

  lock();
  read_client_table();

  if (client[0].pid != 0) {
    /* there's already a master : try to become a slave */
    return;
  }

  if (use_mmap) {
    add_to_filo = add_to_filo_mapped;
    remove_to_filo = remove_to_filo_mapped;
    add_to_fifo = add_to_fifo_mapped;
    remove_to_fifo = remove_to_fifo_mapped;
  }
  else {
    add_to_filo = add_to_filo_notmapped;
    remove_to_filo = remove_to_filo_notmapped;
    add_to_fifo = add_to_fifo_notmapped;
    remove_to_fifo = remove_to_fifo_notmapped;
  }

  /* no other master, let's go */
  set_whoiam();
  write_client_table();
  unlock();

  fprintf(stderr, "Master with pid=%d on %s\n\n", getpid(),
	  client[0].hostname);
  if (use_mmap)
    map_file();

  initscr();			/* initialize Curses */

  for (;; i++) {

    lock();
    read_client_table();
    verify_whoiam();

    if (i % 5 == 0) {
      state++;
      w1 = state;
      for (i = 1; i <= NB_CLIENT_MAX; i++) {
			w2 = w1 % NB_SLAVE_MODE;
			if (client[i].pid != 0)
				client[i].mode = w2 + 1;
			w1 -= w2;
			w1 /= NB_SLAVE_MODE;
      }
      counter++;
    }

    if (use_mmap) {
      get_filo_level_mapped(&filo_level);
      get_fifo_level_mapped(&fifo_start, &fifo_next, &fifo_nb);
    }
    else {
      get_filo_level(&filo_level);
      get_fifo_level(&fifo_start, &fifo_next, &fifo_nb);
    }

    write_client_table();
    unlock();

    display_filo(filo_level);
    display_fifo(fifo_start, fifo_next, fifo_nb);
    display_status(client, filo_level, fifo_nb);

    usleep(200000);
  }
}

/*-------------------------------------------------------------------
   Slave
  -------------------------------------------------------------------*/

static void
slave(void)
{
  int i;
  int old_lock_method;

/* here the file is already open, locked 
   and the table is known */

  for (i = 1; i < NB_CLIENT_MAX + 1; i++) {
    if (client[i].pid == 0) {
      position = i;
      break;
    }
  }

  if (position == 0) {
    /* there's no place for a new slave : inform and quit */
    fprintf(stderr, "there's no place for a new slave\n");
    unlock();
    close(fd);
    exit(EXIT_SUCCESS);
  }

  if (!use_option) {
    /* master options overwrite specified ones */
    old_lock_method = use_flock;
    /* the file is already locked. We backup the previously used method
       to be able to do the next unlock call. */
    use_flock = client[0].info.use_flock;
    use_mmap = client[0].info.use_mmap;
    no_sleep = client[0].info.no_sleep;
  }

  if (use_mmap) {
    add_to_filo = add_to_filo_mapped;
    remove_to_filo = remove_to_filo_mapped;
    add_to_fifo = add_to_fifo_mapped;
    remove_to_fifo = remove_to_fifo_mapped;
  } else {
    add_to_filo = add_to_filo_notmapped;
    remove_to_filo = remove_to_filo_notmapped;
    add_to_fifo = add_to_fifo_notmapped;
    remove_to_fifo = remove_to_fifo_notmapped;
  }

  /* A new slave is going to be created */
  set_whoiam();
  write_client_table();

  /* unlock file with the correct method */
  i = use_flock;
  use_flock = old_lock_method;
  unlock();
  use_flock = i;

  if (verbose)
    fprintf(stderr, "pid=%d\n", getpid());
  if (use_mmap)
    map_file();

  for (;;) {

    lock();
    read_client_table();
    verify_whoiam();
    verify_markers();
    unlock();

    switch (client[position].mode) {
    case BYE:
      bye(SIG_MASTER);
      break;
    case OFF:
      break;
    case FILO_ADD:
      add_to_filo();
      break;
    case FILO_REM:
      remove_to_filo();
      break;
    case FIFO_ADD:
      add_to_fifo();
      break;
    case FIFO_REM:
      remove_to_fifo();
      break;
    default:
      break;
    }
    if (no_sleep == 0)
      usleep((unsigned long) (100000.0 * rand() / (RAND_MAX + 1.0)) + 1);
    counter++;
  }

}

/*-------------------------------------------------------------------
   Quit normally or anormally
  -------------------------------------------------------------------*/

static void
fatal(char *msg)
{
  perror(msg);
  exit(EXIT_FAILURE);
}

static void
bye(int sig)
{
  int i;

  if (position == 0)
    endwin();			/* end Curses */

  switch (sig) {
  case SIG_MASTER:
    fprintf(stderr, "[MASTER]");
    break;
  case SIGTERM:
    fprintf(stderr, "[SIGTERM]");
    break;
  case SIGINT:
    fprintf(stderr, "[SIGINT]");
    break;
  case SIG_TABLE_CORRUPTED:
    fprintf(stderr, "[TABLE_CORRUPTED]");
    break;
  case SIG_FILO_CORRUPTED:
    fprintf(stderr, "[FILO_CORRUPTED]");
    break;
  case SIG_FIFO_CORRUPTED:
    fprintf(stderr, "[FIFO_CORRUPTED]");
    break;
  case SIG_MARKER_CORRUPTED:
    fprintf(stderr, "[MARKER_CORRUPTED]");
    break;
  default:
    fprintf(stderr, "[OTHER]");
    break;
  }
  fprintf(stderr, " bye from pid %d after %d operations ... ", getpid(),
	  counter);

  /* unlock if needed */
  unlock();

  lock();
  read_client_table();

  /* when the master catch a signal,
     all slaves are set in mode "bye" which means "it's time to die" */
  if (position == 0) {
    for (i = 1; i < NB_CLIENT_MAX + 1; i++) {
      if (client[i].pid != 0)
	client[i].mode = BYE;
    }
  }

  /* the slave is removed from the table */
  client[position].pid = 0;
  client[position].mode = OFF;

  write_client_table();
  unlock();
  if (use_mmap)
    unmap_file();
  close(fd);

  fprintf(stderr, "done. \n\n");
  exit(EXIT_SUCCESS);
}

/*-------------------------------------------------------------------
   Reporting
  -------------------------------------------------------------------*/

static void
display_status(CLIENT * client_state, int filo_level, int fifo_level)
{
  int i;
  char info[] = "   ";

  move(0, 0);

  printw("Master \n");
  if (use_flock)
    printw("... using flock instead of fcntl\n");
  if (use_mmap)
    printw("... using memory mapped data\n");
  printw("\n");
  printw("filo level %s = %d      \n", filo_str, filo_level);
  printw("fifo level %s = %d      \n", fifo_str, fifo_level);
  printw("\n");
  for (i = 1; i < NB_CLIENT_MAX + 1; i++) {
    if (client_state[i].pid == 0) {
      printw("#%.2d :\n", i);
    }
    else {
      info[0] = (client[i].info.use_flock) ? 'f' : ' ';
      info[1] = (client[i].info.use_mmap) ? 'm' : ' ';
      info[2] = (client[i].info.no_sleep) ? 'n' : ' ';
      printw("#%.2d : (%s) pid %d on %s in mode %s\n",
	     i, info, client_state[i].pid,
	     client_state[i].hostname, slave_mode_str[client_state[i].mode]);
    }
  }
  refresh();
}

/*-------------------------------------------------------------------
   File Access
  -------------------------------------------------------------------*/

static void
lseek_to(void *what)
{
  if (lseek(fd, (int) what - (int) data, SEEK_SET) < 0)
    fatal("lseek error");
}

static void
lseek_int(int offset, int whence)
{
  if (lseek(fd, offset * sizeof(int), whence) < 0)
    fatal("lseek error");
}

static void
read_int(int *value)
{
  if (read(fd, (char *) value, sizeof(int)) < sizeof(int))
    fatal("unable to read data");
}

static void
write_int(int *value)
{
  if (write(fd, (const char *) value, sizeof(int)) < sizeof(int))
    fatal("unable to write filo data");
}

static void
map_file(void)
{
  /* map file to memory */
  data = (DATA_STRUCT *) mmap(0, sizeof(DATA_STRUCT),
			      (PROT_READ | PROT_WRITE), MAP_SHARED, fd, 0);
  if (data == MAP_FAILED)
    fatal("unable to map the file");
}

static void
synchronize(void)
{
  /* put all modifications in the file */
  msync((void *) data, sizeof(DATA_STRUCT), (MS_SYNC | MS_INVALIDATE));
}

static void
unmap_file(void)
{
  int cr;

  /* unmap memory */
  cr = munmap((void *) data, sizeof(DATA_STRUCT));
  if (cr == -1)
    fatal("unable to ummap memory");
  data = NULL;
}

/*-------------------------------------------------------------------
   Clent table management
  -------------------------------------------------------------------*/

#define CLIENT_SZ sizeof(CLIENT)*(NB_CLIENT_MAX+1)

static CLIENT client_cpy[NB_CLIENT_MAX + 1];
static CLIENT whoiam;

static void
read_client_table(void)
{
  lseek_int(0, SEEK_SET);
  if (read(fd, (char *) client, CLIENT_SZ) < CLIENT_SZ)
    fatal("unable to write client table");
  memcpy((void *) client_cpy, (void *) client, CLIENT_SZ);
}

static void
write_client_table(void)
{
  int i;
  char *original, *modified;

  original = (char *) client_cpy;
  modified = (char *) client;

  lseek_int(0, SEEK_SET);

  for (i = 0; i < CLIENT_SZ; i++) {
    if (*original != *modified) {
      if (write(fd, (const char *) modified, 1) < 1)
	fatal("unable to write client table");
    }
    else {
      if (lseek(fd, 1, SEEK_CUR) < 0)
	fatal("lseek error");
    }
    original++;
    modified++;
  }

}

static void
init_client_table(void)
{
  int i;

  for (i = 0; i < NB_CLIENT_MAX + 1; i++) {
    client[i].info.use_flock = 0;
    client[i].info.use_mmap = 0;
    client[i].info.no_sleep = 0;
    client[i].info.unused = 0;
    client[i].pid = 0;
    client[position].hostname[0] = '\0';
    client[position].mode = OFF;
  }
  lseek_int(0, SEEK_SET);
  if (write(fd, (const char *) client, CLIENT_SZ) < CLIENT_SZ)
    fatal("unable to write client table");
}

static void
set_whoiam(void)
{
  client[position].info.use_flock = use_flock;
  client[position].info.use_mmap = use_mmap;
  client[position].info.no_sleep = no_sleep;
  client[position].info.unused = 0;
  client[position].pid = getpid();
  if (gethostname(client[position].hostname, MAX_HOSTNAME_LENGTH) < 0)
    fatal("get hostname");
  client[position].mode = OFF;
  memcpy((void *) &whoiam, (void *) &client[position], sizeof(CLIENT));
}

static void
verify_whoiam(void)
{
  if (memcmp((void *) &whoiam, (void *) &client[position],
	     sizeof(CLIENT) - sizeof(slave_mode)) != 0)
    bye(SIG_TABLE_CORRUPTED);
}

/*-------------------------------------------------------------------
   Markers management
  -------------------------------------------------------------------*/

static int
_markers(void)
{
  int value;
  int flag = 0;

  lseek_to(&data->marker1);
  read_int(&value);
  if (value != MARKER)
    flag = 1;

  lseek_to(&data->marker2);
  read_int(&value);
  if (value != MARKER)
    flag = 2;

  lseek_to(&data->marker3);
  read_int(&value);
  if (value != MARKER)
    flag = 3;

  return (flag);
}

static int
check_markers(void)
{
  int flag = 0;

  if (verbose)
    fprintf(stderr, "check MARKERs integrity ... ");

  flag = _markers();

  if (flag > 0) {
    if (verbose)
      fprintf(stderr, "\n invalid marker%d\n", flag);
    return (1);
  }

  if (verbose)
    fprintf(stderr, "done.\n");
  return (0);
}

static void
verify_markers(void)
{
  if (_markers() > 0)
    bye(SIG_MARKER_CORRUPTED);
}

/*-------------------------------------------------------------------
   FILO management
  -------------------------------------------------------------------*/

/* FILO [+++++++++++++++.................]    */
/*       ^              ^                ^    */
/*       0             next            size   */

static int
check_filo(void)
{
  int i, filo_next, value;

  if (verbose)
    fprintf(stderr, "check FILO integrity ... ");

  lseek_to(&data->filo.next);
  read_int(&filo_next);

  if ((filo_next < 0) || (filo_next > FILO_SIZE))
    return (1);

  for (i = 0; i < filo_next; i++) {
    read_int(&value);
    if (value != i)
      return (1);
  }
  for (i = filo_next; i < FILO_SIZE; i++) {
    read_int(&value);
    if (value != INT_MAX)
      return (1);
  }

  if (verbose)
    fprintf(stderr, "done.\n");
  return (0);
}

static void
init_filo(void)
{
  int i, filo_next, empty;

  empty = INT_MAX;

  lseek_to(&data->filo.next);
  filo_next = (FILO_SIZE >> 1);
  write_int(&filo_next);
  for (i = 0; i < filo_next; i++) {
    write_int(&i);
  }
  for (i = filo_next; i < FILO_SIZE; i++) {
    write_int(&empty);
  }
}

static void
add_to_filo_notmapped(void)
{
  int filo_next, value;

  lock();

  lseek_to(&data->filo.next);
  read_int(&filo_next);

  if (filo_next < FILO_SIZE) {

    lseek_int(filo_next, SEEK_CUR);

    read_int(&value);

    if (value != INT_MAX)
      bye(SIG_FILO_CORRUPTED);

    /* next position */
    lseek_int(-1, SEEK_CUR);
    write_int(&filo_next);

    filo_next++;
    lseek_to(&data->filo.next);
    write_int(&filo_next);

  }

  unlock();
}

static void
remove_to_filo_notmapped(void)
{
  int filo_next, value, empty;

  empty = INT_MAX;

  lock();

  lseek_to(&data->filo.next);
  read_int(&filo_next);

  if (filo_next > 0) {

    filo_next--;

    /* next position */
    lseek_int(filo_next, SEEK_CUR);

    read_int(&value);

    if (value != filo_next)
      bye(SIG_FILO_CORRUPTED);

    lseek_int(-1, SEEK_CUR);
    write_int(&empty);

    lseek_to(&data->filo.next);
    write_int(&filo_next);

  }

  unlock();

}

static void
display_filo(int level)
{
  int i;

  i = FILO_SIZE / 10;

  level = level + i - 1;
  level = (level - level % i) / i;

  for (i = 0; i < level; i++)
    filo_str[i + 1] = '-';
  for (i = level; i < 10; i++)
    filo_str[i + 1] = ' ';
}

static void
get_filo_level(int *level)
{
  lseek_to(&data->filo.next);
  read_int(level);
}

static void
add_to_filo_mapped(void)
{
  lock();

  if (data->filo.next < FILO_SIZE) {

    if (data->filo.value[data->filo.next] != INT_MAX)
      bye(SIG_FILO_CORRUPTED);

    /* next position */
    data->filo.value[data->filo.next] = data->filo.next;

    data->filo.next++;

    synchronize();
  }

  unlock();
}

static void
remove_to_filo_mapped(void)
{
  lock();

  if (data->filo.next > 0) {

    data->filo.next--;

    if (data->filo.value[data->filo.next] != data->filo.next)
      bye(SIG_FILO_CORRUPTED);

    data->filo.value[data->filo.next] = INT_MAX;

    synchronize();

  }

  unlock();
}

static void
get_filo_level_mapped(int *level)
{
  *level = data->filo.next;
}

/*-------------------------------------------------------------------
   FIFO management
  -------------------------------------------------------------------*/

static int
check_fifo(void)
{
  int i, fifo_start, fifo_next, fifo_nb, value;

  if (verbose)
    fprintf(stderr, "check FIFO integrity ... ");

  get_fifo_level(&fifo_start, &fifo_next, &fifo_nb);
/*   if(verbose) fprintf(stderr,"pointer %d, %d, %d\n",fifo_start, fifo_next, fifo_nb); */

  if ((fifo_start < 0) || (fifo_start >= FIFO_SIZE))
    return (1);
  if ((fifo_next < 0) || (fifo_next >= FIFO_SIZE))
    return (1);
  if ((fifo_nb < 0) || (fifo_nb > FIFO_SIZE))
    return (1);
  if ((fifo_next - fifo_start + FIFO_SIZE) % FIFO_SIZE != fifo_nb % FIFO_SIZE)
    return (1);
/*   if(verbose) fprintf(stderr,"pointers ok\n"); */

  if (fifo_start > fifo_next) {

/*     if(verbose) fprintf(stderr,"case \"start > next\"\n"); */

    /* FIFO [++++....................++++++++]    */
    /*       ^   ^                   ^       ^    */
    /*       0 next                start    size  */

    /* FIFO [...............................+]      */
    /*       ^                              ^^      */
    /*       0=next                    start  size  */

    for (i = 0; i < fifo_next; i++) {
      read_int(&value);
      if (value != i)
	return (1);
    }
/*     if(verbose) fprintf(stderr,"region 1 ok\n"); */

    for (i = fifo_next; i < fifo_start; i++) {
      read_int(&value);
      if (value != INT_MAX)
	return (1);
    }
/*     if(verbose) fprintf(stderr,"region 2 ok\n"); */

    for (i = fifo_start; i < FIFO_SIZE; i++) {
      read_int(&value);
      if (value != i)
	return (1);
    }
/*     if(verbose) fprintf(stderr,"region 3 ok\n"); */

  }
  else if (fifo_start < fifo_next) {

/*     if(verbose) fprintf(stderr,"case \"start < next\"\n"); */

    /* FIFO [....+++++++++++++++++++++.......]    */
    /*       ^   ^                    ^      ^    */
    /*       0 start                next   size   */

    /*  FIFO [+...............................]    */
    /*        ^^                              ^    */
    /* 0=start  next                         size  */

    for (i = 0; i < fifo_start; i++) {
      read_int(&value);
      if (value != INT_MAX)
	return (1);
    }
/*     if(verbose) fprintf(stderr,"region 1 ok\n"); */

    for (i = fifo_start; i < fifo_next; i++) {
      read_int(&value);
      if (value != i)
			return (1);
    }
/*     if(verbose) fprintf(stderr,"region 2 ok\n"); */

    for (i = fifo_next; i < FIFO_SIZE; i++) {
      read_int(&value);
      if (value != INT_MAX)
			return (1);
    }
/*     if(verbose) fprintf(stderr,"region 3 ok\n"); */

  }
  else {

/*     if(verbose) fprintf(stderr,"case \"start == next\"\n"); */

    if (fifo_nb == 0) {

      for (i = 0; i < FIFO_SIZE; i++) {
			read_int(&value);
			if (value != INT_MAX)
				return (1);
      }

    } else {

      for (i = 0; i < FIFO_SIZE; i++) {
			read_int(&value);
			if (value != i)
				return (1);
      }

    }

  }

  if (verbose) fprintf(stderr, "done.\n");
  return (0);
}

static void
init_fifo(void)
{
  int i, fifo_start, fifo_next, fifo_nb, empty;

  empty = INT_MAX;

  fifo_start = 0;
  fifo_next = (FIFO_SIZE >> 1);
  fifo_nb = fifo_next;

  lseek_to(&data->fifo.start);
  write_int(&fifo_start);
  write_int(&fifo_next);
  write_int(&fifo_nb);
  for (i = 0; i < fifo_next; i++)
    write_int(&i);
  for (i = fifo_next; i < FIFO_SIZE; i++)
    write_int(&empty);
}

static void
add_to_fifo_notmapped(void)
{
  int fifo_start, fifo_next, fifo_nb, value;

  lock();

  get_fifo_level(&fifo_start, &fifo_next, &fifo_nb);

  if (fifo_nb < FIFO_SIZE) {

    lseek_int(fifo_next, SEEK_CUR);

    read_int(&value);
    if (value != INT_MAX)
      bye(SIG_FIFO_CORRUPTED);

    lseek_int(-1, SEEK_CUR);
    write_int(&fifo_next);

    fifo_nb++;
    fifo_next = (fifo_next + 1) % FIFO_SIZE;
    lseek_to(&data->fifo.start);
    lseek_int(1, SEEK_CUR);
    write_int(&fifo_next);
    write_int(&fifo_nb);

  }
  unlock();
}

static void
remove_to_fifo_notmapped(void)
{
  int fifo_start, fifo_next, fifo_nb, value, empty;

  empty = INT_MAX;

  lock();

  get_fifo_level(&fifo_start, &fifo_next, &fifo_nb);

  if (fifo_nb > 0) {

    lseek_int(fifo_start, SEEK_CUR);

    read_int(&value);
    if (value != fifo_start)
      bye(SIG_FIFO_CORRUPTED);

    lseek_int(-1, SEEK_CUR);
    write_int(&empty);

    fifo_nb--;
    fifo_start = (fifo_start + 1) % FIFO_SIZE;

    lseek_to(&data->fifo.start);
    write_int(&fifo_start);
    lseek_int(1, SEEK_CUR);
    write_int(&fifo_nb);

  }

  unlock();

}

static void
display_fifo(int start, int next, int nb)
{
  int i, s, n;

  i = FIFO_SIZE / 10;

  if (nb == 0) {
    for (i = 0; i < 10; i++) fifo_str[i + 1] = ' ';
  } else {

    s = start;
    n = next;

    start = start + i - 1;
    start = (start - start % i) / i;

    next = next + i - 2;
    next = (next - next % i) / i;

    if (n > s) {
      for (i = 0; i < start; i++) fifo_str[i + 1] = ' ';
      for (i = start; i < next; i++) fifo_str[i + 1] = '-';
      for (i = next; i < 10; i++) fifo_str[i + 1] = ' ';
    } else {
      for (i = 0; i < next; i++) fifo_str[i + 1] = '-';
      for (i = next; i < start; i++) fifo_str[i + 1] = ' ';
      for (i = start; i < 10; i++) fifo_str[i + 1] = '-';
    }

  }
}

static void
get_fifo_level(int *start, int *next, int *level)
{
  lseek_to(&data->fifo.start);
  read_int(start);
  read_int(next);
  read_int(level);
}

static void
add_to_fifo_mapped(void)
{
  lock();

  if (data->fifo.level < FIFO_SIZE) {

    if (data->fifo.value[data->fifo.next] != INT_MAX)
      bye(SIG_FIFO_CORRUPTED);

    data->fifo.value[data->fifo.next] = data->fifo.next;

    data->fifo.level++;
    data->fifo.next = (data->fifo.next + 1) % FIFO_SIZE;

    synchronize();

  }
  unlock();
}

static void
remove_to_fifo_mapped(void)
{
  lock();

  if (data->fifo.level > 0) {

    if (data->fifo.value[data->fifo.start] != data->fifo.start)
      bye(SIG_FIFO_CORRUPTED);

    data->fifo.value[data->fifo.start] = INT_MAX;

    data->fifo.level--;
    data->fifo.start = (data->fifo.start + 1) % FIFO_SIZE;

    synchronize();

  }
  unlock();
}

static void
get_fifo_level_mapped(int *start, int *next, int *level)
{
  *start = data->fifo.start;
  *next = data->fifo.next;
  *level = data->fifo.level;
}

_______________________________________________
gfs-devel mailing list
gfs-devel@sistina.com
http://lists.sistina.com/mailman/listinfo/gfs-devel
Read the GFS Howto:  http://www.sistina.com/gfs/Pages/howto.html


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic