SlideShare a Scribd company logo
Data::ObjectDriver
        id:clouder
     Yokohama.pm #5
About D::OD
• Author: Benjamin Trott
• Recently Version: 0.06
• Simple, transparent data interface, with
  caching.
• Based on MT::ObjectDriver in MT.
  Now MT included D::OD.
D::OD features
• Built-in supportRAM and Apache inPartitioning.
  Support Memcached,
                     Caching and
                                    caching.

• Have to support master-slaver_handle()/rw_handle().
  Can change process for read/write using
                                          structure in mind.

• Implementation is becauseso less model feature.
  But implement by myself,
                           thin, east-to-use.
                                of
   Has ‘has_a’ but not has ‘has_many’.
Class structures
• Driver definition about how to connection to
  Class for
            class
   db and cache server, and partitioning rules.

• Object classwhat you call.
  The model class
   Class for definition about how to treat data on tables.
Class structures
• Other classes
 - D::OD::ResultSet
   In the middle of an implementation?
      Do not use in MT.

  -   D::OD::Profiler
      Simple profiler.

  -   D::OD::GearmanDBI
      I do not know how to use;)
Simple usase
• Make object class for table
  Make sub-class of D::OD::BaseObject,
   and set table information using install_properties().
   ‘driver’ is D::OD::Driver::DBI.
Simple usage
package Artist;
use strict;
use base qw( Data::ObjectDriver::BaseObject );

__PACKAGE__->install_properties(
   datasource => 'artist',
   columns     => [ qw( id name orig_name band_id ) ],
   primary_key => 'id',
   driver      => Data::ObjectDriver::Driver::DBI->new( %DB_INFO ),
);

1;
CRUD and etc
• Create
my artist = Artist->new(
  name => '                   ',
   fullname => '                         II   '
);
$artist->save;
# or
Artist->bulk_insert( [col1, col2], [ [d1, d2], [d1, d2] ]);
CRUD and etc
  • Read
my $artist = Artist->lookup(1);
print $artist->name;
# or
$artist_iter = Artist->search( { name => '            ' } );
@artists = Artist->search( { name => '           ' );
# or
$artists_ref = Artist->lookup_multi( [ 1, 2, 3 ] );
CRUD and etc
• Update
 $artist->name( '   ' );
 $artist->save;
CRUD and etc
• Delete

 $artist->remove;
CRUD and etc
• has_a()
 __PACKAGE__->has_a( {
     class => 'Band',
     column => 'band_id',
     cached => 1,
 } );
CRUD and etc
• add_trigger() post_load pre_search pre_insert
  pre_save post_save
   post_insert pre_update post_update pre_remove
   post_remove post_inflate

 __PACKAGE__->add_trigger(
    pre_insert => sub {
       my ( $obj, $orig_obj ) = @_;
       ...
    },
 );
Caching
• Only change driver
  If there is not cache,
  connect to db using D::OD::Driver::DBI.
Caching
package Artist;
use strict;
use base qw( Data::ObjectDriver::BaseObject );

__PACKAGE__->install_properties(
   ...
   driver => Data::ObjectDriver::Driver::Cache::Memcached->new(
       cache => Cache::Memcached->new( servers => @servers ),
       fallback => Data::ObjectDriver::Driver::DBI->new( %DB_INFO ),
   ),
   ...
);

1;
Master-Slave structure
• Only override r_handle().in read process,
  r_handle() is method that execute
  so this method is used to connect to slave database.
Master-Slave structure
 • Object class
package Artist;
use strict;
use base qw( Data::ObjectDriver::BaseObject );

__PACKAGE__->install_properties(
   ...
   driver => Data::ObjectDriver::Driver::Cache::Memcached->new(
       cache => Cache::Memcached->new( servers => @servers ),
       fallback => ReplDriver->new( %DB_INFO, slaves => [ slave01, ... ] ),
   ),
   ...
);
Master-Slave structure
 • Driver class
package ReplDriver;
use strict;
use base qw( Data::ObjectDriver::Driver::DBI );

__PACKAGE__->mk_accessors( qw( slaves ) );

sub init {
  my $driver = shift;
  my %param = @_;
  $driver->slaves( delete $param{ slaves } );
  $driver->SUPER::init( %param );
  return $driver;
}

# cont.
Master-Slave structure
 • Driver class(cont.)
# cont.

sub r_handle {
  my $driver = shift;
  my $db = shift || 'main';
  for my $slave ( shuffle @{ $driver->slaves } ) {
     # connect to $slave
     my $dbh = DBI->connect( $slave->{DB_INFO} );
     $driver->dbd->init_dbh($dbh);
     return $dbh;
  }
  $driver->rw_handle($db);
}

1;
Partitioning
package CD;
use strict;
use base qw( Data::ObjectDriver::BaseObject );

__PACKAGE__->install_properties(
   datasource => 'cd',
   columns     => [ qw( artist_id id title ) ],
   primary_key => [ qw( artist_id id ) ],
   driver      => PartitionDriver->driver,
);

1;
Partitioning
package PartitionDriver;
use strict;

sub driver {
  my $fallback = Data::ObjectDriver::Driver::Partition->new(
     get_driver => &find_partition,
  );
  Data::ObjectDriver::Driver::Cache::Memcached->new(
     cache => Cache::Memcached->new( servers => @servers ),
     fallback => $fallback,
  ),
}

# cont.
Partitioning
# cont.

sub find_partition {
  my ( $terms, $args ) = @_;
  my $artist = Artist->lookup( $terms->{ artist_id } );
  return ReplDriver->new(
     %{ $artist->partition_obj->master },
     slaves => $artist->partition_obj->slaves,
     pk_generator => &pk_generator,
  );
}

sub pk_generator {
   my $obj = shift;
   $obj->id( generate_id() );
   1;
},

1;
Partitioning

my $cd = CD->new(
  artist_id => 1,
  title => '      '
);
$cd->save;


lookup() is depends on PartitionDriver implementation in partitioning.
At the end, I wish...
• Built-in support pager using Data::Page.
• Wants count() and more useful methods.
• Hard to execute simple SQL.
  (Just do using D::OD::SQL?)
• And hard to execute ‘JOIN’.
Fin.

More Related Content

About Data::ObjectDriver

  • 1. Data::ObjectDriver id:clouder Yokohama.pm #5
  • 2. About D::OD • Author: Benjamin Trott • Recently Version: 0.06 • Simple, transparent data interface, with caching. • Based on MT::ObjectDriver in MT. Now MT included D::OD.
  • 3. D::OD features • Built-in supportRAM and Apache inPartitioning. Support Memcached, Caching and caching. • Have to support master-slaver_handle()/rw_handle(). Can change process for read/write using structure in mind. • Implementation is becauseso less model feature. But implement by myself, thin, east-to-use. of Has ‘has_a’ but not has ‘has_many’.
  • 4. Class structures • Driver definition about how to connection to Class for class db and cache server, and partitioning rules. • Object classwhat you call. The model class Class for definition about how to treat data on tables.
  • 5. Class structures • Other classes - D::OD::ResultSet In the middle of an implementation? Do not use in MT. - D::OD::Profiler Simple profiler. - D::OD::GearmanDBI I do not know how to use;)
  • 6. Simple usase • Make object class for table Make sub-class of D::OD::BaseObject, and set table information using install_properties(). ‘driver’ is D::OD::Driver::DBI.
  • 7. Simple usage package Artist; use strict; use base qw( Data::ObjectDriver::BaseObject ); __PACKAGE__->install_properties( datasource => 'artist', columns => [ qw( id name orig_name band_id ) ], primary_key => 'id', driver => Data::ObjectDriver::Driver::DBI->new( %DB_INFO ), ); 1;
  • 8. CRUD and etc • Create my artist = Artist->new( name => ' ', fullname => ' II ' ); $artist->save; # or Artist->bulk_insert( [col1, col2], [ [d1, d2], [d1, d2] ]);
  • 9. CRUD and etc • Read my $artist = Artist->lookup(1); print $artist->name; # or $artist_iter = Artist->search( { name => ' ' } ); @artists = Artist->search( { name => ' ' ); # or $artists_ref = Artist->lookup_multi( [ 1, 2, 3 ] );
  • 10. CRUD and etc • Update $artist->name( ' ' ); $artist->save;
  • 11. CRUD and etc • Delete $artist->remove;
  • 12. CRUD and etc • has_a() __PACKAGE__->has_a( { class => 'Band', column => 'band_id', cached => 1, } );
  • 13. CRUD and etc • add_trigger() post_load pre_search pre_insert pre_save post_save post_insert pre_update post_update pre_remove post_remove post_inflate __PACKAGE__->add_trigger( pre_insert => sub { my ( $obj, $orig_obj ) = @_; ... }, );
  • 14. Caching • Only change driver If there is not cache, connect to db using D::OD::Driver::DBI.
  • 15. Caching package Artist; use strict; use base qw( Data::ObjectDriver::BaseObject ); __PACKAGE__->install_properties( ... driver => Data::ObjectDriver::Driver::Cache::Memcached->new( cache => Cache::Memcached->new( servers => @servers ), fallback => Data::ObjectDriver::Driver::DBI->new( %DB_INFO ), ), ... ); 1;
  • 16. Master-Slave structure • Only override r_handle().in read process, r_handle() is method that execute so this method is used to connect to slave database.
  • 17. Master-Slave structure • Object class package Artist; use strict; use base qw( Data::ObjectDriver::BaseObject ); __PACKAGE__->install_properties( ... driver => Data::ObjectDriver::Driver::Cache::Memcached->new( cache => Cache::Memcached->new( servers => @servers ), fallback => ReplDriver->new( %DB_INFO, slaves => [ slave01, ... ] ), ), ... );
  • 18. Master-Slave structure • Driver class package ReplDriver; use strict; use base qw( Data::ObjectDriver::Driver::DBI ); __PACKAGE__->mk_accessors( qw( slaves ) ); sub init { my $driver = shift; my %param = @_; $driver->slaves( delete $param{ slaves } ); $driver->SUPER::init( %param ); return $driver; } # cont.
  • 19. Master-Slave structure • Driver class(cont.) # cont. sub r_handle { my $driver = shift; my $db = shift || 'main'; for my $slave ( shuffle @{ $driver->slaves } ) { # connect to $slave my $dbh = DBI->connect( $slave->{DB_INFO} ); $driver->dbd->init_dbh($dbh); return $dbh; } $driver->rw_handle($db); } 1;
  • 20. Partitioning package CD; use strict; use base qw( Data::ObjectDriver::BaseObject ); __PACKAGE__->install_properties( datasource => 'cd', columns => [ qw( artist_id id title ) ], primary_key => [ qw( artist_id id ) ], driver => PartitionDriver->driver, ); 1;
  • 21. Partitioning package PartitionDriver; use strict; sub driver { my $fallback = Data::ObjectDriver::Driver::Partition->new( get_driver => &find_partition, ); Data::ObjectDriver::Driver::Cache::Memcached->new( cache => Cache::Memcached->new( servers => @servers ), fallback => $fallback, ), } # cont.
  • 22. Partitioning # cont. sub find_partition { my ( $terms, $args ) = @_; my $artist = Artist->lookup( $terms->{ artist_id } ); return ReplDriver->new( %{ $artist->partition_obj->master }, slaves => $artist->partition_obj->slaves, pk_generator => &pk_generator, ); } sub pk_generator { my $obj = shift; $obj->id( generate_id() ); 1; }, 1;
  • 23. Partitioning my $cd = CD->new( artist_id => 1, title => ' ' ); $cd->save; lookup() is depends on PartitionDriver implementation in partitioning.
  • 24. At the end, I wish... • Built-in support pager using Data::Page. • Wants count() and more useful methods. • Hard to execute simple SQL. (Just do using D::OD::SQL?) • And hard to execute ‘JOIN’.
  • 25. Fin.

Editor's Notes