List:Commits« Previous MessageNext Message »
From:msvensson Date:March 26 2007 11:53am
Subject:bk commit into 5.1 tree (msvensson:1.2477)
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of msvensson. When msvensson does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2007-03-26 11:53:01+02:00, msvensson@stripped +5 -0
  Add unittest for mf_tempfile

  include/Makefile.am@stripped, 2007-03-26 11:53:00+02:00, msvensson@stripped +1 -1
    Add my_vector.h and ThreadRunner.h 

  include/ThreadRunner.h@stripped, 2007-03-26 11:53:00+02:00, msvensson@stripped +232 -0
    Add helper class for easily testing with multiple threads

  include/ThreadRunner.h@stripped, 2007-03-26 11:53:00+02:00, msvensson@stripped +0 -0

  include/my_vector.h@stripped, 2007-03-26 11:53:00+02:00, msvensson@stripped +139 -0
    Add helper class for maintaining a dynamic list

  include/my_vector.h@stripped, 2007-03-26 11:53:00+02:00, msvensson@stripped +0 -0

  mysys/my_winthread.c@stripped, 2007-03-26 11:53:00+02:00, msvensson@stripped +4 -3
    Update windows implementation of 'pthread_create' to allow
    "attr" argument to be NULL

  unittest/mysys/mf_tempfile-t.cc@stripped, 2007-03-26 11:53:00+02:00, msvensson@stripped
+104 -0
    Add mf_tempfile-t unit test program for mf_tempfile

  unittest/mysys/mf_tempfile-t.cc@stripped, 2007-03-26 11:53:00+02:00, msvensson@stripped
+0 -0

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	msvensson
# Host:	pilot.blaudden
# Root:	/home/msvensson/mysql/bug26233/my51-bug26233

--- 1.77/include/Makefile.am	2006-12-31 01:06:32 +01:00
+++ 1.78/include/Makefile.am	2007-03-26 11:53:00 +02:00
@@ -37,7 +37,7 @@ noinst_HEADERS =	config-win.h config-net
 			mysql_version.h.in my_handler.h my_time.h decimal.h \
 			my_vle.h my_user.h my_atomic.h atomic/nolock.h \
 			atomic/rwlock.h atomic/x86-gcc.h atomic/x86-msvc.h \
-			my_libwrap.h
+			my_libwrap.h my_vector.h ThreadRunner.h
 
 # Remove built files and the symlinked directories
 CLEANFILES =            $(BUILT_SOURCES) readline openssl

--- 1.13/mysys/my_winthread.c	2006-12-23 20:04:08 +01:00
+++ 1.14/mysys/my_winthread.c	2007-03-26 11:53:00 +02:00
@@ -78,11 +78,11 @@ int pthread_create(pthread_t *thread_id,
   pthread_mutex_lock(&THR_LOCK_thread);
 #ifdef __BORLANDC__
   hThread=(HANDLE)_beginthread((void(_USERENTRY *)(void *)) pthread_start,
-			       attr->dwStackSize ? attr->dwStackSize :
+			       attr && attr->dwStackSize ? attr->dwStackSize :
 			       65535, (void*) map);
 #else
   hThread=(HANDLE)_beginthread((void( __cdecl *)(void *)) pthread_start,
-			       attr->dwStackSize ? attr->dwStackSize :
+			       attr && attr->dwStackSize ? attr->dwStackSize :
 			       65535, (void*) map);
 #endif
   DBUG_PRINT("info", ("hThread=%lu",(long) hThread));
@@ -96,7 +96,8 @@ int pthread_create(pthread_t *thread_id,
 	       ("Can't create thread to handle request (error %d)",error));
     DBUG_RETURN(error ? error : -1);
   }
-  VOID(SetThreadPriority(hThread, attr->priority)) ;
+  VOID(SetThreadPriority(hThread,
+                         attr && attr->priority ? attr->priority : 0));
   DBUG_RETURN(0);
 }
 
--- New file ---
+++ include/ThreadRunner.h	07/03/26 11:53:00

#include <my_global.h>
#include <my_sys.h>
#include <my_vector.h>
#include <my_pthread.h>
#include <m_string.h>

#ifndef MYSQL_THREAD_RUNNER_H
#define MYSQL_THREAD_RUNNER_H


struct ThreadContext {
  my_thread_id tid;

  ThreadContext() {};
  ~ThreadContext() {};
};

pthread_handler_t run_thread(void* arg);

typedef int (thread_runner_func)(ThreadContext* ctx);

class ThreadRunner {

//  friend pthread_handler(run_thread);
public:

  enum ThreadStatus {
    TR_UNDEFINED,
    TR_STARTED,
    TR_COMPLETED,
  };

  class Thread {
  public:
    Thread(ThreadRunner* _parent,
           thread_runner_func* _func) :
      parent(_parent), func(_func), result(0), status(TR_UNDEFINED) { }
    ~Thread() {};

    void completed(int res)
    {
      result= res;
      status= TR_COMPLETED;
      parent->completed();
    }

    ThreadRunner* parent;
    thread_runner_func* func;
    pthread_t handle;
    int result;
    ThreadStatus status;
    ThreadContext context;
  };

public:
  ThreadRunner(unsigned _max_time= 0) :
    threads_completed(0), max_time(_max_time)
  {
    my_init();
    pthread_mutex_init(&wait_threads_mutex, MY_MUTEX_INIT_SLOW);
    pthread_cond_init(&wait_threads_cond, NULL);
  };
  ~ThreadRunner()
  {
    clear();
    pthread_mutex_destroy(&wait_threads_mutex);
    pthread_cond_destroy(&wait_threads_cond);
    my_end(MY_CHECK_ERROR);
  };

  /* Add function to be run in thread */
  int add(thread_runner_func* func,
          unsigned count);

  /* Start all threads and wait for them to return */
  int execute();

  /* Start threads */
  int start();

  /* Wait for started threads to return */
  int wait();

  /* Set max time for threads to run */
  int set_max_time(unsigned max_seconds);

  /* Check if all threads returned specified error */
  bool error(int err){
    bool result= true;
    for (unsigned i= 0; i < threads.size(); i++)
    {
      if (threads[i]->result != err)
      {
        fprintf(stderr, "thread %d failed\n", i);
        result= false;
      }
    }
    return result;
  }

  /* Check if all threads returned sucess */
  bool ok(){
    return error(0);
  }



  void clear(){
    for (unsigned i= 0; i < threads.size(); i++)
      delete threads[i];
    threads.clear();
  }

private:
  Vector<Thread*> threads;
  pthread_mutex_t wait_threads_mutex;
  pthread_cond_t wait_threads_cond;
  unsigned threads_completed;
  unsigned max_time;

  /*
    Called by thread when it has completed

    Count number of completed threads and
    signal cond if this was the last
  */
  void completed()
  {
    pthread_mutex_lock(&wait_threads_mutex);
    threads_completed++;
    if(threads_completed == threads.size())
      pthread_cond_signal(&wait_threads_cond);
    pthread_mutex_unlock(&wait_threads_mutex);
  }

};

int ThreadRunner::add(thread_runner_func* func,
                      unsigned count)
{
  for (unsigned i= 0; i < count; i++)
  {
    Thread* thread= new Thread(this, func);
    threads.push_back(thread);
  }
  return 0;
}


int ThreadRunner::execute()
{
  if (start())
    return 1;
  if(wait())
    return 1;
  return 0;
}


pthread_handler_t run_thread(void* arg)
{
  ThreadRunner::Thread* thread= (ThreadRunner::Thread*)arg;
  my_thread_init();
  thread->context.tid= my_thread_dbug_id();
  int res= thread->func(&thread->context);
  thread->completed(res);
  my_thread_end();
  return 0;
}


int ThreadRunner::start()
{
  int result= 0;

  pthread_mutex_lock(&wait_threads_mutex);
  threads_completed= 0;
  for (unsigned i = 0; i < threads.size(); i++)
  {
    Thread* thread= threads[i];
    if (pthread_create(&thread->handle,
                       NULL,
                       run_thread,
                       (void*)thread) != 0)
    {
      fprintf(stderr, "Could not create thread %d\n", i);
      result= 1;
      break;
    }
    thread->status= TR_STARTED;
    thread->result= -1;

  }
  pthread_mutex_unlock(&wait_threads_mutex);
  return result;
}

int ThreadRunner::wait()
{
  pthread_mutex_lock(&wait_threads_mutex);

  while(threads_completed < threads.size())
    pthread_cond_wait(&wait_threads_cond,
                      &wait_threads_mutex);
  DBUG_ASSERT(threads_completed == threads.size());

  pthread_mutex_unlock(&wait_threads_mutex);

#ifdef __WIN__
  /* 
    All threads have signaled their completion
    and called '_threadend' from 'pthread_exit'.
    Thus the thread handle is closed and it's
    not possible to join the thread
  */
#else
  for(unsigned i= 0; i < threads.size(); i++)
  {
    void* unused;
    Thread* thread= threads[i];
    pthread_join(thread->handle, &unused);
  }
#endif
  return 0;
}


template class Vector<ThreadRunner::Thread*>;


#endif

--- New file ---
+++ include/my_vector.h	07/03/26 11:53:00
/* Copyright (C) 2003 MySQL AB

   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; version 2 of the License.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef MYSQL_VECTOR_H
#define MYSQL_VECTOR_H

template<class T>
class Vector {
public:
  Vector(int sz = 10);
  ~Vector();

  T& operator[](unsigned i);
  const T& operator[](unsigned i) const;
  unsigned size() const { return current_size; };

  void push_back(const T &);
  T& back();

  void erase(unsigned index);

  void clear();

  void fill(unsigned new_size, T & obj);

  Vector<T>& operator=(const Vector<T>&);

private:
  T * items;
  unsigned current_size;
  unsigned increment_size;
  unsigned alloced_size;
};

template<class T>
Vector<T>::Vector(int sz){
  items = new T[sz];
  current_size = 0;
  alloced_size = sz;
  increment_size = 50;
}

template<class T>
Vector<T>::~Vector(){
  delete[] items;
  /* safety for placement new usage */
  items = 0;
  current_size = 0;
  alloced_size = 0;
}

template<class T>
T &
Vector<T>::operator[](unsigned i){
  if(i >= current_size)
    abort();
  return items[i];
}

template<class T>
const T &
Vector<T>::operator[](unsigned i) const {
  if(i >= current_size)
    abort();
  return items[i];
}

template<class T>
T &
Vector<T>::back(){
  return (* this)[current_size - 1];
}

template<class T>
void
Vector<T>::push_back(const T & t){
  if(current_size == alloced_size){
    T * tmp = new T [alloced_size + increment_size];
    if(!tmp)
      abort();
    for (unsigned k = 0; k < current_size; k++)
      tmp[k] = items[k];
    delete[] items;
    items = tmp;
    alloced_size = alloced_size + increment_size;
  }
  items[current_size] = t;
  current_size++;
}

template<class T>
void
Vector<T>::erase(unsigned i){
  if(i >= current_size)
    abort();

  for (unsigned k = i; k + 1 < current_size; k++)
    items[k] = items[k + 1];
  current_size--;
}

template<class T>
void
Vector<T>::clear(){
  current_size = 0;
}

template<class T>
void
Vector<T>::fill(unsigned new_size, T & obj){
  while(current_size <= new_size)
    push_back(obj);
}

template<class T>
Vector<T>&
Vector<T>::operator=(const Vector<T>& obj){
  if(this != &obj){
    clear();
    for(size_t i = 0; i<obj.size(); i++){
      push_back(obj[i]);
    }
  }
  return * this;
}

#endif

--- New file ---
+++ unittest/mysys/mf_tempfile-t.cc	07/03/26 11:53:00
/* Copyright (C) 2006 MySQL AB

   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; version 2 of the License.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include "ThreadRunner.h"
#include <errno.h>
#include <tap.h>

char tmpdir[FN_REFLEN]= {0};

/*
  for (loop)
    1. create temporary file
    2. fill file with random number of bytes, first byte
       written is set to the random value and then increased
       by one for each written byte
    3. read back filled data and verify length and content
*/
int test_create_temporary_file(ThreadContext* ctx)
{
  char temp_file_path[FN_REFLEN];
  char write_buf[256];
  char read_buf[256];
  File fd;
  for (int loop= 0; loop < 1000; loop++)
  {
    /* Open temporary file */
    if ((fd= create_temp_file(temp_file_path, tmpdir[0] ? tmpdir : NULL,
                              "tst",
                              O_RDWR | O_CREAT | O_SHARE | O_SHORT_LIVED | O_TEMPORARY,
                              MYF(MY_WME))) < 0)
      return my_errno;

    // fprintf(stderr, "temp_file_path: %s\n", temp_file_path);

    for (unsigned i= 0; i < sizeof(write_buf); i++)
      write_buf[i]= (char)((ctx->tid + loop + i) % 256);

    /* Write bitpattern to the file */
    if (my_write(fd, (byte*)write_buf, sizeof(write_buf),
                 MYF(MY_FNABP | MY_WME)))
    {
      my_close(fd, MYF(0));
      return 1;
    }

    my_seek(fd, 0, MY_SEEK_SET, MYF(0));
    /* Read bitpattern from the file */
    if (my_read(fd, (byte*)read_buf, sizeof(read_buf),
                 MYF(MY_FNABP | MY_WME)))
    {
      my_close(fd, MYF(0));
      return 1;
    }
    my_close(fd, MYF(0));

    /* Check that the file does not exist */
    if (!access(to, F_OK))
      return 2;

    if (memcmp(write_buf, read_buf, sizeof(read_buf)))
      return 1;
  }
  return 0;
}


int main()
{
  ThreadRunner runner;
  const int num_threads= 10;
  plan(2);
  /*
    Run with tmpdir set to NULL
  */
  runner.add(test_create_temporary_file, num_threads);
  runner.execute();

  ok(runner.ok(), "Created temporary files, with %d threads", num_threads);

  /*
    Run the test a second time with tempdir set to current dir
    allow EACCESS as a valid error
  */
  my_getwd(tmpdir, sizeof(tmpdir), MYF(0));
  runner.execute();

  ok(runner.ok() || runner.error(EACCES),
     "Created temporary files in %s, with %d threads", tmpdir, num_threads);

  return exit_status();
}


Thread
bk commit into 5.1 tree (msvensson:1.2477)msvensson26 Mar