~posulliv/drizzle/memcached_applier

« back to all changes in this revision

Viewing changes to drizzled/plugin/storage_engine.cc

  • Committer: Jay Pipes
  • Date: 2009-08-03 14:23:22 UTC
  • mfrom: (1039.2.68 staging)
  • mto: This revision was merged to the branch mainline in revision 1078.
  • Revision ID: jpipes@serialcoder-20090803142322-1g67h7su9mocg9ig
Merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
#include <drizzled/plugin_registry.h>
32
32
#include <string>
33
33
 
 
34
#include <drizzled/table_proto.h>
 
35
 
 
36
#include <google/protobuf/io/zero_copy_stream.h>
 
37
#include <google/protobuf/io/zero_copy_stream_impl.h>
 
38
 
 
39
#include <mysys/my_dir.h>
 
40
 
34
41
#include CSTDINT_H
35
42
 
36
43
using namespace std;
72
79
  savepoint_alloc_size-= orig_savepoint_offset;
73
80
}
74
81
 
75
 
 
76
 
/* args: current_session, db, name */
77
 
int StorageEngine::table_exists_in_engine(Session*, const char *, const char *)
78
 
{
79
 
  return HA_ERR_NO_SUCH_TABLE;
80
 
}
81
 
 
82
82
void StorageEngine::setTransactionReadWrite(Session* session)
83
83
{
84
84
  Ha_trx_info *ha_info= &session->ha_data[getSlot()].ha_info[0];
128
128
  @return
129
129
    pointer to storage engine plugin handle
130
130
*/
131
 
StorageEngine *ha_resolve_by_name(Session *session, const LEX_STRING *name)
 
131
StorageEngine *ha_resolve_by_name(Session *session, std::string find_str)
132
132
{
133
 
 
134
 
  string find_str(name->str, name->length);
135
133
  transform(find_str.begin(), find_str.end(),
136
134
            find_str.begin(), ::tolower);
137
135
  string default_str("default");
138
136
  if (find_str == default_str)
139
137
    return ha_default_storage_engine(session);
140
 
    
141
138
 
142
139
  StorageEngine *engine= all_engines.find(find_str);
143
140
 
424
421
  return 0;
425
422
}
426
423
 
427
 
/**
428
 
  Ask handler if the table exists in engine.
429
 
  @retval
430
 
    HA_ERR_NO_SUCH_TABLE     Table does not exist
431
 
  @retval
432
 
    HA_ERR_TABLE_EXIST       Table exists
433
 
  @retval
434
 
    \#                  Error code
435
 
*/
436
 
 
437
 
class TableExistsInStorageEngine: public unary_function<StorageEngine *,bool>
438
 
{
439
 
  Session *session;
440
 
  const char *db;
441
 
  const char *name;
 
424
static int drizzle_read_table_proto(const char* path, drizzled::message::Table* table)
 
425
{
 
426
  int fd= open(path, O_RDONLY);
 
427
 
 
428
  if (fd == -1)
 
429
    return errno;
 
430
 
 
431
  google::protobuf::io::ZeroCopyInputStream* input=
 
432
    new google::protobuf::io::FileInputStream(fd);
 
433
 
 
434
  if (table->ParseFromZeroCopyStream(input) == false)
 
435
  {
 
436
    delete input;
 
437
    close(fd);
 
438
    return -1;
 
439
  }
 
440
 
 
441
  delete input;
 
442
  close(fd);
 
443
  return 0;
 
444
}
 
445
 
 
446
class StorageEngineGetTableProto: public unary_function<StorageEngine *,bool>
 
447
{
 
448
  const char* path;
 
449
  drizzled::message::Table *table_proto;
 
450
  int *err;
442
451
public:
443
 
  TableExistsInStorageEngine(Session *session_arg,
444
 
                             const char *db_arg, const char *name_arg)
445
 
    :session(session_arg), db(db_arg), name(name_arg) {}
 
452
  StorageEngineGetTableProto(const char* path_arg,
 
453
                             drizzled::message::Table *table_proto_arg,
 
454
                             int *err_arg)
 
455
  :path(path_arg), table_proto(table_proto_arg), err(err_arg) {}
 
456
 
446
457
  result_type operator() (argument_type engine)
447
458
  {
448
 
    int ret= engine->table_exists_in_engine(session, db, name);
449
 
    return ret == HA_ERR_TABLE_EXIST;
450
 
  } 
 
459
    int ret= engine->getTableProtoImplementation(path, table_proto);
 
460
 
 
461
    if (ret != ENOENT)
 
462
      *err= ret;
 
463
 
 
464
    return *err == EEXIST;
 
465
  }
451
466
};
452
467
 
453
468
/**
455
470
  to ask engine if there are any new tables that should be written to disk
456
471
  or any dropped tables that need to be removed from disk
457
472
*/
458
 
int ha_table_exists_in_engine(Session* session,
459
 
                              const char* db, const char* name,
460
 
                              StorageEngine **engine_arg)
 
473
int StorageEngine::getTableProto(const char* path,
 
474
                                 drizzled::message::Table *table_proto)
461
475
{
462
 
  StorageEngine *engine= NULL;
463
 
  bool found= false;
 
476
  int err= ENOENT;
464
477
 
465
478
  drizzled::Registry<StorageEngine *>::iterator iter=
466
479
    find_if(all_engines.begin(), all_engines.end(),
467
 
            TableExistsInStorageEngine(session, db, name));
468
 
  if (iter != all_engines.end()) 
469
 
  {
470
 
    engine= *iter;
471
 
    found= true;
472
 
  }
473
 
  else
474
 
  {
475
 
    /* Default way of knowing if a table exists. (checking .frm exists) */
476
 
 
477
 
    char path[FN_REFLEN];
478
 
    size_t length;
479
 
    length= build_table_filename(path, sizeof(path),
480
 
                                 db, name, false);
481
 
 
482
 
    if ((table_proto_exists(path) == EEXIST))
483
 
      found= true;
484
 
 
485
 
    if (found && engine_arg)
 
480
            StorageEngineGetTableProto(path, table_proto, &err));
 
481
  if (iter == all_engines.end())
 
482
  {
 
483
    string proto_path(path);
 
484
    string file_ext(".dfe");
 
485
    proto_path.append(file_ext);
 
486
 
 
487
    int error= access(proto_path.c_str(), F_OK);
 
488
 
 
489
    if (error == 0)
 
490
      err= EEXIST;
 
491
    else
 
492
      err= errno;
 
493
 
 
494
    if (table_proto)
486
495
    {
487
 
      drizzled::message::Table table;
488
 
      strcpy(path + length, ".dfe");
489
 
      if (drizzle_read_table_proto(path, &table) == 0)
490
 
      {
491
 
        LEX_STRING engine_name= { (char*)table.engine().name().c_str(),
492
 
                                 strlen(table.engine().name().c_str()) };
493
 
        engine= ha_resolve_by_name(session, &engine_name);
494
 
      }
 
496
      int read_proto_err= drizzle_read_table_proto(proto_path.c_str(),
 
497
                                                   table_proto);
 
498
 
 
499
      if (read_proto_err)
 
500
        err= read_proto_err;
495
501
    }
496
502
  }
497
503
 
498
 
  if (found == false)
499
 
    return HA_ERR_NO_SUCH_TABLE;
500
 
 
501
 
  if (engine_arg)
502
 
    *engine_arg= engine;
503
 
 
504
 
  return HA_ERR_TABLE_EXIST;
 
504
  return err;
505
505
}
506
506
 
507
 
int StorageEngine::renameTableImpl(Session *, const char *from, const char *to)
 
507
 
 
508
int StorageEngine::renameTableImplementation(Session *, const char *from, const char *to)
508
509
{
509
510
  int error= 0;
510
511
  for (const char **ext= bas_ext(); *ext ; ext++)
535
536
  @retval
536
537
    !0  Error
537
538
*/
538
 
int StorageEngine::deleteTableImpl(Session *, const std::string table_path)
 
539
int StorageEngine::deleteTableImplementation(Session *, const std::string table_path)
539
540
{
540
541
  int error= 0;
541
542
  int enoent_or_zero= ENOENT;                   // Error if no file was deleted
557
558
  return error;
558
559
}
559
560
 
560
 
static const char *check_lowercase_names(handler *file, const char *path,
561
 
                                         char *tmp_path)
562
 
{
563
 
  if ((file->ha_table_flags() & HA_FILE_BASED))
564
 
    return path;
565
 
 
566
 
  /* Ensure that table handler get path in lower case */
567
 
  if (tmp_path != path)
568
 
    strcpy(tmp_path, path);
569
 
 
570
 
  /*
571
 
    we only should turn into lowercase database/table part
572
 
    so start the process after homedirectory
573
 
  */
574
 
  my_casedn_str(files_charset_info, tmp_path + drizzle_data_home_len);
575
 
  return tmp_path;
576
 
}
577
 
 
578
561
/**
579
562
  An interceptor to hijack the text of the error message without
580
563
  setting an error in the thread. We need the text to present it
637
620
    else
638
621
      return;
639
622
 
640
 
    path= check_lowercase_names(tmp_file, path, tmp_path);
 
623
    path= engine->checkLowercaseNames(path, tmp_path);
641
624
    const std::string table_path(path);
642
625
    int tmp_error= engine->deleteTable(session, table_path);
643
626
 
644
 
    if(tmp_error!=ENOENT)
 
627
    if (tmp_error != ENOENT)
645
628
    {
 
629
      if (tmp_error == 0)
 
630
      {
 
631
        if (engine->check_flag(HTON_BIT_HAS_DATA_DICTIONARY))
 
632
          delete_table_proto_file(path);
 
633
        else
 
634
          tmp_error= delete_table_proto_file(path);
 
635
      }
 
636
 
646
637
      *dt_error= tmp_error;
647
638
      if(*file)
648
639
        delete *file;
676
667
  for_each(all_engines.begin(), all_engines.end(),
677
668
           DeleteTableStorageEngine(session, path, &file, &error));
678
669
 
 
670
  if (error == ENOENT) /* proto may be left behind */
 
671
    error= delete_table_proto_file(path);
 
672
 
679
673
  if (error && generate_warning)
680
674
  {
681
675
    /*
733
727
int ha_create_table(Session *session, const char *path,
734
728
                    const char *db, const char *table_name,
735
729
                    HA_CREATE_INFO *create_info,
736
 
                    bool update_create_info)
 
730
                    bool update_create_info,
 
731
                    drizzled::message::Table *table_proto)
737
732
{
738
733
  int error= 1;
739
734
  Table table;
740
 
  char name_buff[FN_REFLEN];
741
 
  const char *name;
742
735
  TableShare share(db, 0, table_name, path);
743
736
 
744
 
  if (open_table_def(session, &share) ||
745
 
      open_table_from_share(session, &share, "", 0, (uint32_t) READ_ALL, 0, &table,
746
 
                            OTM_CREATE))
 
737
  if (table_proto)
 
738
  {
 
739
    if (parse_table_proto(session, *table_proto, &share))
 
740
      goto err;
 
741
  }
 
742
  else
 
743
  {
 
744
    if (open_table_def(session, &share))
 
745
      goto err;
 
746
  }
 
747
 
 
748
  if (open_table_from_share(session, &share, "", 0, (uint32_t) READ_ALL, 0,
 
749
                            &table, OTM_CREATE))
747
750
    goto err;
748
751
 
749
752
  if (update_create_info)
750
753
    table.updateCreateInfo(create_info);
751
754
 
752
 
  name= check_lowercase_names(table.file, share.path.str, name_buff);
753
 
 
754
 
  error= share.storage_engine->createTable(session, name, &table, create_info);
 
755
  error= share.storage_engine->createTable(session, path, &table,
 
756
                                           create_info, table_proto);
755
757
  table.closefrm(false);
756
758
  if (error)
757
759
  {
 
760
    char name_buff[FN_REFLEN];
758
761
    sprintf(name_buff,"%s.%s",db,table_name);
759
762
    my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), name_buff, error);
760
763
  }
769
772
  return engine == NULL ? string("UNKNOWN") : engine->getName();
770
773
}
771
774
 
 
775
const char *StorageEngine::checkLowercaseNames(const char *path, char *tmp_path)
 
776
{
 
777
  if (flags.test(HTON_BIT_FILE_BASED))
 
778
    return path;
 
779
 
 
780
  /* Ensure that table handler get path in lower case */
 
781
  if (tmp_path != path)
 
782
    strcpy(tmp_path, path);
 
783
 
 
784
  /*
 
785
    we only should turn into lowercase database/table part
 
786
    so start the process after homedirectory
 
787
  */
 
788
  my_casedn_str(files_charset_info, tmp_path + drizzle_data_home_len);
 
789
 
 
790
  return tmp_path;
 
791
}
 
792
 
 
793
class DFETableNameIterator: public TableNameIteratorImplementation
 
794
{
 
795
private:
 
796
  MY_DIR *dirp;
 
797
  uint32_t current_entry;
 
798
 
 
799
public:
 
800
  DFETableNameIterator(const std::string &database)
 
801
  : TableNameIteratorImplementation(database),
 
802
    dirp(NULL),
 
803
    current_entry(-1)
 
804
    {};
 
805
 
 
806
  ~DFETableNameIterator();
 
807
 
 
808
  int next(std::string *name);
 
809
 
 
810
};
 
811
 
 
812
DFETableNameIterator::~DFETableNameIterator()
 
813
{
 
814
  if (dirp)
 
815
    my_dirend(dirp);
 
816
}
 
817
 
 
818
int DFETableNameIterator::next(string *name)
 
819
{
 
820
  char uname[NAME_LEN + 1];
 
821
  FILEINFO *file;
 
822
  char *ext;
 
823
  uint32_t file_name_len;
 
824
  const char *wild= NULL;
 
825
 
 
826
  if (dirp == NULL)
 
827
  {
 
828
    bool dir= false;
 
829
    char path[FN_REFLEN];
 
830
 
 
831
    build_table_filename(path, sizeof(path), db.c_str(), "", false);
 
832
 
 
833
    dirp = my_dir(path,MYF(dir ? MY_WANT_STAT : 0));
 
834
 
 
835
    if (dirp == NULL)
 
836
    {
 
837
      if (my_errno == ENOENT)
 
838
        my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), db.c_str());
 
839
      else
 
840
        my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), path, my_errno);
 
841
      return(ENOENT);
 
842
    }
 
843
    current_entry= -1;
 
844
  }
 
845
 
 
846
  while(true)
 
847
  {
 
848
    current_entry++;
 
849
 
 
850
    if (current_entry == dirp->number_off_files)
 
851
    {
 
852
      my_dirend(dirp);
 
853
      dirp= NULL;
 
854
      return -1;
 
855
    }
 
856
 
 
857
    file= dirp->dir_entry + current_entry;
 
858
 
 
859
    if (my_strcasecmp(system_charset_info, ext=fn_rext(file->name),".dfe") ||
 
860
        is_prefix(file->name, TMP_FILE_PREFIX))
 
861
      continue;
 
862
    *ext=0;
 
863
 
 
864
    file_name_len= filename_to_tablename(file->name, uname, sizeof(uname));
 
865
 
 
866
    uname[file_name_len]= '\0';
 
867
 
 
868
    if (wild && wild_compare(uname, wild, 0))
 
869
      continue;
 
870
 
 
871
    if (name)
 
872
      name->assign(uname);
 
873
 
 
874
    return 0;
 
875
  }
 
876
}
 
877
 
 
878
TableNameIterator::TableNameIterator(const std::string &db)
 
879
  : current_implementation(NULL), database(db)
 
880
{
 
881
  engine_iter= all_engines.begin();
 
882
  default_implementation= new DFETableNameIterator(database);
 
883
}
 
884
 
 
885
TableNameIterator::~TableNameIterator()
 
886
{
 
887
  delete current_implementation;
 
888
}
 
889
 
 
890
int TableNameIterator::next(std::string *name)
 
891
{
 
892
  int err= 0;
 
893
 
 
894
next:
 
895
  if (current_implementation == NULL)
 
896
  {
 
897
    while(current_implementation == NULL && engine_iter != all_engines.end())
 
898
    {
 
899
      StorageEngine *engine= *engine_iter;
 
900
      current_implementation= engine->tableNameIterator(database);
 
901
      engine_iter++;
 
902
    }
 
903
 
 
904
    if (current_implementation == NULL && engine_iter == all_engines.end())
 
905
    {
 
906
      current_implementation= default_implementation;
 
907
    }
 
908
  }
 
909
 
 
910
  err= current_implementation->next(name);
 
911
 
 
912
  if (err == -1)
 
913
  {
 
914
    if (current_implementation != default_implementation)
 
915
    {
 
916
      delete current_implementation;
 
917
      current_implementation= NULL;
 
918
      goto next;
 
919
    }
 
920
  }
 
921
 
 
922
  return err;
 
923
}
 
924