IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Jun 25, 2009, 2:00:56 PM (17 years ago)
Author:
eugene
Message:

merging changes from head

Location:
branches/eam_branches/20090522
Files:
15 deleted
16 edited
16 copied

Legend:

Unmodified
Added
Removed
  • branches/eam_branches/20090522

  • branches/eam_branches/20090522/Nebulous-Server

  • branches/eam_branches/20090522/Nebulous-Server/Build.PL

    r23932 r24557  
    1010    requires            => {
    1111        'Apache2::Const'        => 0,
     12        'Cache::Memcached'      => 0,
    1213        'Class::Accessor::Fast' => 0,
    1314        'Config::YAML'          => '1.42',
  • branches/eam_branches/20090522/Nebulous-Server/Changes

    r23932 r24557  
    22
    330.17
     4    - add basic valid key caching via memcached
     5    - add params checking to Nebulous::Key::parse_neb_key()
     6    - restrict creation/modification/remove of xattrs to the user.* namespace
     7    - add chmod_object() method
    48    - retry database transactions when a deadlock is detected
    59    - add log4perl logging to nebdiskd
     
    1620    - change 'log_level' param to 'trace'
    1721    - refactor ->find_objects() functionality
     22    - rename Nebulous::Key->soft_volume Nebulous::Key->hard_volume and invert
     23      the semantics
     24    - add nebdiskd mountpoint test retyring
     25    - rework delete_instance() to avoid requiring an index on instance.uri
     26    - nebdiskd bug fixes: fix debug mode outpoint going to mail, remove db
     27      passwd requirement (not all dbs require a password param)
     28    - completely rework how mountedvol is populated, drop mount table
     29    - infinitely try to get a db handle if the connection fails
     30    - add --mountpoint param to neb-voladd
    1831     
    19320.16
  • branches/eam_branches/20090522/Nebulous-Server/MANIFEST

    r23932 r24557  
    3333t/01_load.t
    3434t/02_config.t
    35 t/02_server_setup.t
    36 t/03_server_create_object.t
    37 t/04_server_replicate_object.t
    38 t/05_server_lock_object.t
    39 t/06_server_unlock_object.t
    40 t/07_server_find_instances.t
    41 t/08_server_delete_instance.t
    42 t/09_server_stat_object.t
    43 t/10_server_is_valid_volume_name.t
    44 t/11_server_is_valid_object_key.t
    45 t/12_server_find_objects.t
    46 t/13_server_rename_object.t
    47 t/14_server_xattr.t
    48 t/15_mounts.t
    49 t/16_server_swap_objects.t
     35t/03_server_setup.t
     36t/04_server_create_object.t
     37t/05_server_replicate_object.t
     38t/06_server_lock_object.t
     39t/07_server_unlock_object.t
     40t/08_server_find_instances.t
     41t/09_server_delete_instance.t
     42t/10_server_stat_object.t
     43t/11_server_is_valid_volume_name.t
     44t/12_server_is_valid_object_key.t
     45t/13_server_find_objects.t
     46t/14_server_rename_object.t
     47t/15_server_xattr.t
     48t/16_mounts.t
     49t/17_server_swap_objects.t
     50t/18_server_chmod_object.t
    5051t/75_parse_neb_key.t
  • branches/eam_branches/20090522/Nebulous-Server/bin/neb-voladd

    r23348 r24557  
    1919use Pod::Usage qw( pod2usage );
    2020
    21 my ($db, $dbhost, $dbuser, $dbpass, $vname, $vhost, $uri);
     21my ($db, $dbhost, $dbuser, $dbpass, $mountpoint, $vname, $vhost, $uri);
    2222
    2323$db     = $ENV{'NEB_DB'} unless $db;
     
    2929    'db|d=s'            => \$db,
    3030    'host=s'            => \$dbhost,
     31    'mountpoint|m=s'    => \$mountpoint,
     32    'pass|p=s'          => \$dbpass,
     33    'uri|u=s'           => \$uri,
    3134    'user|u=s'          => \$dbuser,
    32     'pass|p=s'          => \$dbpass,
     35    'vhost=s'           => \$vhost,
    3336    'vname|n=s'         => \$vname,
    34     'vhost=s'           => \$vhost,
    35     'uri|u=s'           => \$uri,
    3637) || pod2usage( 2 );
    3738
    3839pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
    39 pod2usage( -msg => "Required options: --db --user --pass --vname --vhost --uri", -exitval => 2 )
    40     unless $db && $dbuser && $dbpass && $vname && $vhost && $uri;
     40pod2usage( -msg => "Required options: --db --user --pass --mountpoint --vname --vhost --uri", -exitval => 2 )
     41    unless $db && $dbuser && $dbpass && $mountpoint && $vname && $vhost && $uri;
    4142
    4243my $dbh = DBI->connect(
     
    5960    die "path: $path dirived from URI: $uri does not exist";
    6061}
     62unless (-d $mountpoint) {
     63    die "path: $mountpoint does not exist";
     64}
    6165
    6266print " OK\n";
     
    6569
    6670my $query = $dbh->prepare( $sql->new_volume );
    67 $query->execute( $vname, $vhost, $path );
     71$query->execute( $vname, $vhost, $path, $mountpoint);
    6872
    6973print " OK\n";
     
    128132Optional.  Defaults to C<localhost>.
    129133
     134=item * --mountpoint <path>
     135
     136Path to the mountpoint of the filesystem on which C<--uri> resides.
    130137
    131138=back
  • branches/eam_branches/20090522/Nebulous-Server/bin/nebdiskd

    r23675 r24557  
    11#!/usr/bin/env perl
    22
    3 # Copyright (C) 2007  Joshua Hoblitt
    4 #
    5 # $Id: nebdiskd,v 1.14 2008-10-16 22:51:34 jhoblitt Exp $
     3# Copyright (C) 2007-2009  Joshua Hoblitt
    64
    75use strict;
     
    3533    $user,
    3634    $group,
     35    $retry,
    3736);
    3837
    3938GetOptions(
    40     'dbhost|h=s'    => \$dbhost,
     39    'dbhost|H=s'    => \$dbhost,
    4140    'dbpass|p=s'    => \$dbpass,
    4241    'dbuser|u=s'    => \$dbuser,
     
    4645    'pidfile=s'     => \$pidfile,
    4746    'restart|r'     => \$restart,
     47    'retry=i'       => \$retry,
    4848    'stop|s'        => \$stop,
    49     'user=s'        => \$user,
     49    'user|U=s'      => \$user,
    5050    'verbose|v'     => \$verbose,
    5151) || pod2usage( 2 );
     
    6161$dbhost     ||= $c->get_dbhost  || $ENV{'NEB_DBHOST'} || 'localhost';
    6262$dbuser     ||= $c->get_dbuser  || $ENV{'NEB_USER'};
    63 $dbpass     ||= $c->get_dbpass  || $ENV{'NEB_PASS'};
     63$dbpass     ||= $c->get_dbpass  || $ENV{'NEB_PASS'} || undef;
    6464$pidfile    ||= $c->get_pidfile || "/var/tmp/nebdiskd";
    6565$user       ||= $c->get_user    || $<; # user
    6666$group      ||= $c->get_group   || $); # group
    67 
    68 my $mounts = $c->get_mounts;
     67$retry      ||= $c->get_retry   || 1;
     68
     69#my $mounts = $c->get_mounts;
    6970my $poll_interval = $c->get_poll_interval || 5;
    7071
     
    8081$c->set_pidfile($pidfile);
    8182$c->set_poll_interval($poll_interval);
     83$c->set_retry($retry);
    8284$c->write;
    8385
    8486pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
    85 pod2usage( -msg => "Required options: --db --user --pass", -exitval => 2 )
    86     unless $db && $dbuser && $dbpass;
     87pod2usage( -msg => "Required options: --db --dbuser", -exitval => 2 )
     88    unless $db && $dbuser;
    8789
    8890# start up logging
     
    108110    log4perl.appender.Mailer.to      = ps-ipp-ops@ifa.hawaii.edu
    109111    log4perl.appender.Mailer.subject = nebdiskd alert
    110     log4perl.appender.AppError.Filter= MatchWarn
     112    log4perl.appender.Mailer.buffered = 0
     113    log4perl.appender.Mailer.Filter= MatchWarn
    111114    log4perl.appender.Mailer.layout = Log::Log4perl::Layout::PatternLayout
    112115    log4perl.appender.Mailer.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} | %H | %p | %M - %m%n
     116
     117    log4perl.appender.Limiter              = Log::Log4perl::Appender::Limit
     118    log4perl.appender.Limiter.appender     = Mailer
     119    log4perl.appender.Limiter.block_period = 300
    113120';
    114121Log::Log4perl::init(\$conf);
     
    136143                poll_interval   => $poll_interval,
    137144                debug           => $debug,
     145                retry           => $retry,
    138146        );
    139147    };
     
    155163    my $dbhost          = $p{dbhost} or return;
    156164    my $dbuser          = $p{dbuser} or return;
    157     my $dbpass          = $p{dbpass} or return;
     165#    my $dbpass          = $p{dbpass} or return;
    158166    my $poll_interval   = $p{poll_interval} || 60;
    159167    my $debug           = $p{debug} || 0;
     168    my $retry           = $p{retry} || 1;
    160169
    161170    # setup the db on every pass incase the database died on us
     
    168177
    169178    eval {
    170         my $r_query = $dbh->prepare_cached("REPLACE INTO mount VALUES(?, ?, ?)");
    171         my $d_query = $dbh->prepare_cached("DELETE FROM mount WHERE mountpoint = ?");
    172 
     179        my $r_query = $dbh->prepare_cached("REPLACE INTO mountedvol SELECT *, ?, ? FROM volume WHERE mountpoint = ?");
     180        my $d_query = $dbh->prepare_cached("DELETE FROM mountedvol WHERE mountpoint = ?");
     181
     182        # get list of mount points
     183        my $mounts = [];
     184        {
     185            # there may be multiple vol_ids per mountpoint but we only need to
     186            # check each mointpont once
     187            my $query = $dbh->prepare_cached("SELECT DISTINCT mountpoint FROM volume");
     188            $query->execute;
     189            while (my $row = $query->fetchrow_hashref) {
     190                push @$mounts, $row;
     191            }
     192            $query->finish;
     193        }
     194       
    173195        # determine valid mountpoints
    174196        foreach my $mnt (@$mounts) {
    175             $log->debug("checking $mnt");
     197            my $mountpoint = $mnt->{'mountpoint'};
     198            $log->debug("checking $mountpoint");
    176199            # this /SHOULD/ fail if the mount point is handled by the
    177200            # automounter and it fails to mount
    178             eval {
    179                 unless (is_mountpoint($mnt)) {
     201            my $tries = 0;
     202            TEST: eval {
     203                $tries++;
     204                unless (is_mountpoint($mountpoint)) {
    180205                    $log->warn("$mnt is not a valid mountpoint");
    181206                }
    182207            };
    183208            if ($@) {
     209                # try is_mountpoint() again if $retry > 1
     210                if ($tries < $retry) {
     211                    $log->warn("retrying test of $mountpoint");
     212                    goto TEST;
     213                }
    184214                $log->warn($@);
    185                 $d_query->execute($mnt);
     215                $d_query->execute($mountpoint);
    186216                next;
    187217            }
     
    190220            # we determine if it's a valid mountpoint incase
    191221            # is_mountpoint() invokes the automounter
    192             my $dev_info = df($mnt, 1024);
     222            my $dev_info = df($mountpoint, 1024);
    193223            unless (defined $dev_info) {
    194                 $log->error("can't find device info for $mnt");
     224                $log->error("can't find device info for $mountpoint");
    195225                next;
    196226            }
    197227
    198             $r_query->execute($mnt, @$dev_info{qw( blocks used )});
    199             $log->debug("adding $mnt to db");
     228            # find vol_id(s) for mountpoint
     229            $r_query->execute(@$dev_info{qw( blocks used )}, $mountpoint);
     230            $log->debug("adding $mountpoint to db");
    200231
    201232        }
    202233
    203         $dbh->do("call getmountedvol()");
    204 
    205         $dbh->commit;
    206         $log->debug("commited to database");
     234#        $dbh->do("call getmountedvol()");
     235
     236#        $dbh->commit;
     237#        $log->debug("commited to database");
    207238    };
    208239    if ($@) {
    209         $dbh->rollback;
    210         $log->debug("rolledback transaction");
     240#        $dbh->rollback;
     241#        $log->debug("rolledback transaction");
    211242        $log->logdie($@);
    212243    }
     
    235266    my %p = @_;
    236267
     268    # $p{dbpass} may be undef;
     269
    237270    return unless defined $p{db}
    238271              and defined $p{dbhost}
    239               and defined $p{dbuser}
    240               and defined $p{dbpass};
     272              and defined $p{dbuser};
    241273
    242274    my $sql = Nebulous::Server::SQL->new;
     
    249281            RaiseError => 1,
    250282            PrintError => 1,
    251             AutoCommit => 0,
     283            AutoCommit => 1, # don't want this to be trasnactional
    252284        },
    253285    );
     
    255287    eval {
    256288        $dbh->do( $sql->set_transaction_model );
    257         $dbh->commit;
     289#        $dbh->commit;
    258290    };
    259291    if ($@) {
    260         $dbh->rollback;
     292#        $dbh->rollback;
    261293        $log->logdie($@);
    262294    }
     
    344376=head1 SYNOPSIS
    345377
    346     nebdiskd [--db <db name>] [--user <db username>] [--pass <db password>] [--debug] [--pidfile <filename>] [--stop] [--restart] [--verbose]
     378    nebdiskd [--db|-D <db name>] [--dbhost|-H <db hostname>
     379    [--dbuser|-u <db username>] [--dbpass|-p <db password>] [--debug|-d]
     380    [--user|-U <username>] [--group|-g <groupname>] [--pidfile <filename>]
     381    [--retry <n>] [--stop|-s] [--restart|-r] [--verbose|-v]
    347382
    348383=head1 DESCRIPTION
     
    355390=over 4
    356391
    357 =item * --db|-d <db name>
     392=item * --db|-D <db name>
    358393
    359394Name of database (C<namespace>) to write too.
     
    362397variable is set.
    363398
    364 =item * --user|-u <db username>
     399=item * --dbuser|-u <username>
    365400
    366401Username to authenticate with.
     
    369404variable is set.
    370405
    371 =item * --pass|-p <db password>
     406=item * --dbpass|-p <password>
    372407
    373408Password to authenticate with.
     409
     410Optional if defined in the F<.nebdiskdrc> file or the appropriate environment
     411variable is set or if the database does not require a password.
     412
     413=item * --dbhost|-H <hostname>
     414
     415Database host to connect to.
    374416
    375417Optional if defined in the F<.nebdiskdrc> file or the appropriate environment
    376418variable is set.
    377419
    378 =item * --debug
     420=item * --debug|-d
    379421
    380422This flag prevents the program from "daemonizing" so output can be sent to
     
    397439instance.
    398440
    399 =item * --verbose|-r
     441=item * --retry
     442
     443The number of times to test a mountpoint for "mountedness" before giving up on
     444it.
     445
     446=item * --verbose|-v
    400447
    401448Turns on informational/debugging messages to be sent to the
     
    403450with C<--debug>.
    404451
     452=item * --user|-U
     453
     454user account to run daemon as.
     455
     456=item * --group|-g
     457
     458group to run daemon as.
     459
    405460=back
    406461
     
    415470=item * C<NEB_DB>
    416471
    417 Equivalent to --db|-d
     472Equivalent to --db|-D
    418473
    419474=item * C<NEB_USER>
    420475
    421 Equivalent to --user|-u
     476Equivalent to --dbuser|-u
    422477
    423478=item * C<NEB_PASS>
    424479
    425 Equivalent to --pass|-p
     480Equivalent to --dbpass|-p
    426481
    427482=back
     
    439494    dbpass: '@neb@'
    440495    dbuser: nebulous
    441     mounts:
    442       - /mnt
    443       - /tmp
    444       - /usr
    445496    pidfile: /var/tmp/nebdiskd
    446497    poll_interval: 5
     498    retry: 3
    447499
    448500The values C<db>, C<dbpass>, C<dbuser>, and C<pidfile> have the same semantics
     
    451503=over 4
    452504
    453 =item * C<mounts>
    454 
    455 A list of "paths" to C<stat(2)> before mounted volumes are polled.  The propose
    456 of this option is to attempt to keep "automounted" volumes mounted while this
    457 program is running.
    458 
    459505This value may be omitted or left blank.
    460506
     
    465511This value may be omitted or left blank.  The default value is C<60>s.
    466512
     513=item * C<retry>
     514
     515Same as C<--retry>.
     516
    467517=back
    468518
     
    481531=head1 COPYRIGHT
    482532
    483 Copyright (C) 2007  Joshua Hoblitt.  All rights reserved.
     533Copyright (C) 2007-2009  Joshua Hoblitt.  All rights reserved.
    484534
    485535This program is free software; you can redistribute it and/or modify it under
  • branches/eam_branches/20090522/Nebulous-Server/lib/Nebulous/Key.pm

    r23932 r24557  
    88use warnings FATAL => qw( all );
    99
    10 our $VERSION = '0.02';
     10our $VERSION = '0.03';
    1111
    1212use base qw( Exporter Class::Accessor::Fast );
     
    1414use File::Spec;
    1515use URI::file;
     16use Carp qw( croak );
    1617use URI;
    1718use overload '""' => \&_stringify_key;
     
    2223);
    2324
    24 __PACKAGE__->mk_ro_accessors(qw( path volume soft_volume ));
     25__PACKAGE__->mk_ro_accessors(qw( path volume hard_volume ));
    2526
    2627sub parse_neb_key
    2728{
    2829    my ($key, $volume) = @_;
    29     return unless defined $key;
     30
     31    croak "key param is not optional" unless defined $key;
     32    croak "too many params" if scalar @_ > 2;
    3033
    3134    # white space is not allowed
    3235    if ($key =~ qr/\s+/) {
    33         die "keys and URIs may not contain whitespace";
     36        croak "keys and URIs may not contain whitespace";
    3437    }
    3538
     
    3942   
    4043    my $volume_name;
    41     my $soft_volume;
     44    my $hard_volume;
    4245    # if this is a valid uri
    4346    if (defined $scheme) {
    4447        # if so, does it use the neb scheme?
    45         die "URI does not use the 'neb' scheme"
     48        croak "URI does not use the 'neb' scheme"
    4649            unless $scheme eq 'neb';
    4750
     
    5861        # path component to it
    5962        unless (length $path) {
    60             die "neb URI scheme requires a path component";
     63            croak "neb URI scheme requires a path component";
    6164        }
    6265       
     
    6871        if (defined $volume_info->{volume} and $volume_info->{volume} ne 'any') {
    6972            $volume_name = $volume_info->{volume};
    70             $soft_volume = $volume_info->{soft_volume};
     73            $hard_volume = $volume_info->{hard_volume};
    7174        }
    7275
    7376        # require a leading slash if there is no volume name
    7477        if ((not defined $volume_name) and (not $path =~ m|^/|)) {
    75             die "neb URI scheme requires a leading slash, eg. neb:/";
     78            croak "neb URI scheme requires a leading slash, eg. neb:/";
    7679        }
    7780    } else {
     
    8184        if (defined $volume_info->{volume} and $volume_info->{volume} ne 'any') {
    8285            $volume_name = $volume_info->{volume};
    83             $soft_volume = $volume_info->{soft_volume};
     86            $hard_volume = $volume_info->{hard_volume};
    8487        }
    8588    }
     
    9699    return __PACKAGE__->new({
    97100        volume      => $volume_name,
    98         soft_volume => $soft_volume,
     101        hard_volume => $hard_volume,
    99102        path        => $path,
    100103    });
     
    107110    return unless defined $volume;
    108111
    109     my $soft_volume;
     112    my $hard_volume;
    110113    # check to see if there is a tilde and remove it if found
    111     unless (defined $volume and $volume =~ s/^~//) {
    112         $soft_volume = 1;
     114    if (defined $volume and $volume =~ s/^~//) {
     115        $hard_volume = 1;
    113116    }
    114117
    115     return({ volume => $volume, soft_volume => $soft_volume });
     118    return({ volume => $volume, hard_volume => $hard_volume });
    116119}
    117120
     
    122125
    123126    my $path        = $self->path;
    124     my $volume      = $self->volume || "";
    125     my $soft_volume = $self->soft_volume ? '~' : "";
    126 
    127     return "neb://${soft_volume}${volume}/$path";
     127    my $volume      = $self->volume || '';
     128    my $hard_volume = $self->hard_volume ? '~' : '';
     129
     130    return "neb://${hard_volume}${volume}/$path";
    128131}
    129132
  • branches/eam_branches/20090522/Nebulous-Server/lib/Nebulous/Server.pm

    r23932 r24557  
    1313use base qw( Class::Accessor::Fast );
    1414
     15use Cache::Memcached;
    1516use DBI;
    1617use Digest::SHA1 qw( sha1_hex );
     18use Fcntl ':mode';
    1719use File::Basename qw( basename dirname fileparse );
    1820use File::ExtAttr qw( setfattr );
     
    2729use URI::file;
    2830
    29 __PACKAGE__->mk_accessors(qw( log sql config ));
    30 
    31 use constant SUBPATH_DEPTH  => 2;
    32 use constant NFS_RETRIES    => 100;
     31__PACKAGE__->mk_accessors(qw( log sql config cache ));
     32
     33use constant SUBPATH_DEPTH      => 2;
     34use constant NFS_RETRIES        => 100;
     35use constant NFS_RETRY_WAIT     => 1;
     36use constant TRANS_RETRY_WAIT   => 1;
     37
     38# transaction restart/retry regex
     39my $trans_regex = qr/Deadlock Found|Lock wait timeout exceeded|try restarting transaction|Can't connect to MySQL server/i;
    3340
    3441sub new
     
    4552sub new_from_config
    4653{
    47     my ($class, $config) = @_;
     54    my $class = shift;
     55
     56    my ($config) = @_;
    4857
    4958    # log4perl is not avaliable until we call init()
     
    5160    my $log = Log::Log4perl::get_logger( "Nebulous::Server" );
    5261    $log->level($config->trace);
     62    $log->debug( "entered - @_" );
    5363
    5464    my $sql = Nebulous::Server::SQL->new;
    55 
    56     $log->debug( "entered - @_" );
    5765
    5866    my $self = bless {}, ref $class || $class;
     
    6068    $self->sql($sql);
    6169    $self->config($config);
     70    $self->cache(
     71        Cache::Memcached->new({
     72            servers => $config->memcached_servers,
     73       })
     74    );
     75#    $self->cache->set("foo", "bar") or die "set failed";
     76#    $self->cache->get("foo") or die "get failed";
     77    $log->logdie("at least one database must be defined") unless $config->n_db;
     78
     79    # cause a db session to be started
     80    $self->_db_for_index(0);
    6281
    6382    $log->debug( "leaving" );
     
    7089sub _db_index_for_key
    7190{
    72     my ($self, $key) = @_;
     91    my $self = shift;
     92
     93    my $log     = $self->log;
     94    $log->debug( "entered - @_" );
     95
     96    my ($key) = @_;
    7397
    7498    my $config  = $self->config;
    7599
    76100    my $db_index = 0;
    77     die "key not defined" unless defined $key;
     101    $log->logdie("key not defined") unless defined $key;
    78102
    79103    # hash the key to select the correct database instance
     
    85109    $db_index = unpack("h8", sha1_hex($path)) % $config->n_db;
    86110
     111    $log->debug("index is $db_index");
     112    $log->debug("leaving");
     113
    87114    return $db_index;
    88115}
     
    90117sub _db_for_index
    91118{
    92     my ($self, $db_index) = @_;
     119    my $self = shift;
    93120
    94121    my $log     = $self->log;
     122    $log->debug( "entered - @_" );
     123
     124    my ($db_index) = @_;
     125
    95126    my $sql     = $self->sql;
    96127    my $config  = $self->config;
     
    108139    # lookup database info
    109140    my $db_config = $config->db($db_index);
    110     die "can't find database configuration info for database # $db_index"
     141    $log->logdie("can't find database configuration info for db # $db_index")
    111142        unless $db_config;
    112143
     
    116147    # processes and the database might have gone away on us.  Apache::DBI will
    117148    # take care of getting a valid dbh back.
    118     eval {
    119         $dbh = DBI->connect_cached(
    120             $db_config->dsn,
    121             $db_config->dbuser,
    122             $db_config->dbpasswd,
    123             {
    124                 RaiseError => 1,
    125                 PrintError => 0,
    126                 AutoCommit => 0,
    127             },
    128         );
    129 
    130         $dbh->do( $sql->set_transaction_model );
    131         $log->debug( "connected to database: ", sub { $dbh->data_sources; } );
    132         $dbh->commit;
    133         $log->debug("commit");
    134     };
    135     if ( $@ ) {
    136         $dbh->rollback if $dbh;
    137         $log->debug("rollback");
    138         $log->logdie( "database error: $@" );
     149    TRANS: while (1) {
     150        eval {
     151            $dbh = DBI->connect_cached(
     152                $db_config->dsn,
     153                $db_config->dbuser,
     154                $db_config->dbpasswd,
     155                {
     156                    RaiseError => 1,
     157                    PrintError => 0,
     158                    AutoCommit => 0,
     159                },
     160            );
     161
     162            $dbh->do( $sql->set_transaction_model );
     163            $log->debug( "connected to database: ", sub { $dbh->data_sources; } );
     164            $dbh->commit;
     165            $log->debug("commit");
     166        };
     167        if ($@) {
     168            $dbh->rollback if $dbh;
     169            $log->debug("rollback") if $dbh;
     170            if ($@ =~ qr/Can't connect to MySQL server/) {
     171                $log->warn("database error, retrying transaction: $@");
     172                sleep TRANS_RETRY_WAIT;
     173                redo TRANS;
     174            }
     175            $log->logdie( "database error: $@" );
     176        }
     177        last;
    139178    }
    140179
    141180    $self->{dbs}[$db_index] = $dbh;
    142181
     182    $log->debug("leaving");
     183
    143184    return $dbh;
    144185}
     
    148189    my $self = shift;
    149190
     191    my $log     = $self->log;
     192    $log->debug( "entered - @_" );
     193
    150194    my ($key) = validate_pos(@_,
    151195        {
     
    154198    );
    155199
    156     my $log     = $self->log;
    157200    my $sql     = $self->sql;
    158201    my $config  = $self->config;
    159202
    160     die "key not defined" unless defined $key;
     203    $log->logdie("key not defined") unless defined $key;
    161204    my $db_index = $self->_db_index_for_key($key);
    162205
    163206    my $dbh = $self->_db_for_index($db_index);
     207
    164208    return $dbh;
    165209}
     
    168212{
    169213    my $self = shift;
     214
     215    my $log = $self->log;
     216    $log->debug( "entered - @_" );
    170217
    171218    my ($key, $vol_name) = validate_pos(@_,
     
    186233    );
    187234
     235    my $sql = $self->sql;
     236
    188237    # vol_name overrides the key implied volume
    189     $key = parse_neb_key($key, $vol_name);
     238    eval {
     239        $key = parse_neb_key($key, $vol_name);
     240    };
     241    $log->logdie("$@") if $@;
    190242    $vol_name = $key->volume;
    191243
    192     my $log = $self->log;
    193     my $sql = $self->sql;
    194244    my $db  = $self->db($key);
    195 
    196     $log->debug( "entered - @_" );
    197245
    198246    # the key's volume can't be validiated on input for this method so we have
     
    200248    if (defined $vol_name
    201249        and not $self->_is_valid_volume_name($key, $key->volume)) {
    202         if ($key->soft_volume) {
     250        unless ($key->hard_volume) {
    203251            $log->warn( "$vol_name is not a known volume name" );
    204252            $vol_name = undef;
    205253        } else {
    206             die "$vol_name is not a valid volume name"
     254           $log->logdie("$vol_name is not a valid volume name");
    207255        }
    208256    }
    209257       
    210258    my ($vol_id, $vol_host, $vol_path, $vol_xattr)
    211         = $self->_get_storage_volume($key, $vol_name, $key->soft_volume);
     259        = $self->_get_storage_volume($key, $vol_name, $key->hard_volume);
    212260
    213261    my $parent_id = $self->_resolve_dir_parent_id(key => $key, create => 1);
     
    282330            $db->rollback;
    283331            $log->debug("rollback");
    284             if ($@ =~ /Deadlock found/) {
    285                 $log->warn("database deadlock retrying transaction: $@");
     332            if ($@ =~ $trans_regex) {
     333                $log->warn("database error, retrying transaction: $@");
     334                sleep TRANS_RETRY_WAIT;
    286335                redo TRANS;
    287336            }
     
    291340    }
    292341
     342    # add new key to the cache
     343    $self->cache->set($key->path, 1) if defined $self->cache;
     344    $log->debug( "key added to cache" );
     345
    293346    $log->debug("leaving");
    294347
     
    300353{
    301354    my $self = shift;
     355
     356    my $log = $self->log;
     357    $log->debug( "entered - @_" );
    302358
    303359    my %p = validate(@_,
     
    322378    my $key = $p{key};
    323379
    324     my $log = $self->log;
    325380    my $sql = $self->sql;
    326381    my $db  = $self->db($key);
    327 
    328     $log->debug( "entered - @_" );
    329382
    330383    # no path means '/', which has a dir_id & parent_id of 1
     
    394447                    $query->finish;
    395448                }
    396                 $log->logdie("failed to get LAST_INSERT_ID()")
     449                die("failed to get LAST_INSERT_ID()")
    397450                    unless $parent_id;
    398451
    399                 $db->commit;
     452#                $db->commit;
    400453            }
    401454        };
     
    403456            $db->rollback;
    404457            $log->debug("rollback");
    405             if ($@ =~ /Deadlock found/) {
    406                 $log->warn("database deadlock retrying transaction: $@");
     458            if ($@ =~ $trans_regex) {
     459                $log->warn("database error, retrying transaction: $@");
     460                $parent_id = 1;
     461                sleep TRANS_RETRY_WAIT;
    407462                redo TRANS;
    408463            }
     464            if ($@ =~ qr/Duplicate entry/) {
     465                $log->warn("Duplicate database entry, retrying transaction: $@");
     466                $parent_id = 1;
     467                sleep TRANS_RETRY_WAIT;
     468                redo TRANS;
     469            }
    409470            $log->logdie("error: $@");
    410471        }
     
    421482{
    422483    my $self = shift;
     484
     485    my $log = $self->log;
     486    $log->debug("entered - @_");
    423487
    424488    my ($key, $newkey) = validate_pos(@_,
     
    438502    );
    439503
     504    my $sql = $self->sql;
     505
    440506    # ignore volumes
    441     $key    = parse_neb_key($key);
    442     $newkey = parse_neb_key($newkey);
    443 
    444     my $log = $self->log;
    445     my $sql = $self->sql;
     507    eval {
     508        $key = parse_neb_key($key);
     509    };
     510    $log->logdie("$@") if $@;
     511    eval {
     512        $newkey = parse_neb_key($newkey);
     513    };
     514    $log->logdie("$@") if $@;
     515
    446516    my $db  = $self->db($key);
    447 
    448     $log->debug("entered - @_");
    449517
    450518    # XXX this may require database migration in the future
     
    464532            unless ($rows == 1) {
    465533                $query->finish;
    466                 $log->logdie("affected row count is $rows instead of 1");
    467             }
     534                die("affected row count is $rows instead of 1");
     535            }
     536
     537            $self->cache->delete($key->path) if defined $self->cache;
     538            $self->cache->set($newkey->path, 1) if defined $self->cache;
    468539
    469540            $db->commit;
     
    473544            $db->rollback;
    474545            $log->debug("rollback");
    475             if ($@ =~ /Deadlock found/) {
    476                 $log->warn("database deadlock retrying transaction: $@");
     546            if ($@ =~ $trans_regex) {
     547                $log->warn("database error, retrying transaction: $@");
     548                sleep TRANS_RETRY_WAIT;
    477549                redo TRANS;
    478550            }
     
    491563    my $self = shift;
    492564
     565    my $log = $self->log;
     566    $log->debug("entered - @_");
     567
    493568    my ($key1, $key2) = validate_pos(@_,
    494569        {
     
    506581    );
    507582
     583    my $sql = $self->sql;
     584
    508585    # ignore volumes
    509     $key1 = parse_neb_key($key1);
    510     $key2 = parse_neb_key($key2);
    511 
    512     my $log = $self->log;
    513     my $sql = $self->sql;
     586    eval {
     587        $key1 = parse_neb_key($key1);
     588    };
     589    $log->logdie("$@") if $@;
     590    eval {
     591        $key2 = parse_neb_key($key2);
     592    };
     593    $log->logdie("$@") if $@;
    514594
    515595    my $dbidx1 = $self->_db_index_for_key($key1);
    516596    my $dbidx2 = $self->_db_index_for_key($key2);
    517     die "cannot swap keys not stored on the same database" unless ($dbidx1 == $dbidx2);
     597    $log->logdie("cannot swap keys not stored on the same database")
     598        unless ($dbidx1 == $dbidx2);
    518599
    519600    my $dbh1 = $self->_db_for_index($dbidx1);
    520601    my $dbh2 = $self->_db_for_index($dbidx2);
    521     die "different db handles for the same db?" unless ($dbh1 == $dbh2);
    522 
    523     $log->debug("entered - @_");
     602    $log->logdie("different db handles for the same db?")
     603        unless ($dbh1 == $dbh2);
    524604
    525605    # order of operations for the swap with a single db is:
     
    543623              unless ($rows == 1) {
    544624                  $query->finish;
    545                   $log->logdie("affected row count is $rows instead of 1");
     625                  die("affected row count is $rows instead of 1");
    546626              }
    547627          }
     
    556636              unless ($rows == 1) {
    557637                  $query->finish;
    558                   $log->logdie("affected row count is $rows instead of 1");
     638                  die("affected row count is $rows instead of 1");
    559639              }
    560640          }
     
    569649              unless ($rows == 1) {
    570650                  $query->finish;
    571                   $log->logdie("affected row count is $rows instead of 1");
     651                  die("affected row count is $rows instead of 1");
    572652              }
    573653          }
     
    579659            $db->rollback;
    580660            $log->debug("rollback");
    581             if ($@ =~ /Deadlock found/) {
    582                 $log->warn("database deadlock retrying transaction: $@");
     661            if ($@ =~ $trans_regex) {
     662                $log->warn("database error, retrying transaction: $@");
     663                sleep TRANS_RETRY_WAIT;
    583664                redo TRANS;
    584665            }
     
    612693    my $self = shift;
    613694
     695    my $log = $self->log;
     696    $log->debug("entered - @_");
     697
    614698    my ($key, $vol_name) = validate_pos(@_,
    615699        {
     
    633717    );
    634718
     719    my $sql = $self->sql;
     720
    635721    # if a volume name is explicity specified then we should make the
    636722    # replication onto that volume (even if there is alread an instance on that
     
    642728
    643729    # vol_name overrides the key implied volume
    644     $key = parse_neb_key($key, $vol_name);
     730    eval {
     731        $key = parse_neb_key($key, $vol_name);
     732    };
     733    $log->logdie("$@") if $@;
    645734    $vol_name = $key->volume;
    646735
    647     my $log = $self->log;
    648     my $sql = $self->sql;
    649736    my $db  = $self->db($key);
    650 
    651     $log->debug("entered - @_");
    652737
    653738    if (defined $vol_name
    654739        and not $self->_is_valid_volume_name($key, $key->volume)) {
    655         if ($key->soft_volume) {
     740        unless ($key->hard_volume) {
    656741            $log->warn( "$vol_name is not a known volume name" );
    657742            $vol_name = undef;
    658743        } else {
    659             die "$vol_name is not a valid volume name"
     744           $log->logdie("$vol_name is not a valid volume name");
    660745        }
    661746    }
     
    681766                unless ( $rows > 0 ) {
    682767                    $query->finish;
    683                     $log->logdie( "storage object does not exist" );
     768                    die( "storage object does not exist" );
    684769                }
    685770
     
    725810            $db->rollback;
    726811            # handle soft volumes
    727             if (defined $vol_name and defined $key->soft_volume) {
     812            if (defined $vol_name and not defined $key->hard_volume) {
    728813                $log->debug("retrying with 'any' volume");
    729814                return $self->replicate_object($key->path, 'any');
    730815            }
    731816            $log->debug("rollback");
    732             if ($@ =~ /Deadlock found/) {
    733                 $log->warn("database deadlock retrying transaction: $@");
     817            if ($@ =~ $trans_regex) {
     818                $log->warn("database error, retrying transaction: $@");
     819                sleep TRANS_RETRY_WAIT;
    734820                redo TRANS;
    735821            }
     
    739825    }
    740826
     827    # check to see if the user.mode xattr exists
     828    eval {
     829        my $mode = $self->getxattr_object("$key", 'user.mode');
     830        if (defined $mode) {
     831            $self->chmod_object("$key", $mode);
     832        }
     833    };
     834    if ($@) {
     835        unless ($@ =~ qr/user.mode does not exist/) {
     836            $log->logdie("error: $@");
     837        }
     838    }
     839
    741840    $log->debug("leaving");
    742841
     
    748847{
    749848    my $self = shift;
     849
     850    my $log = $self->log;
     851    $log->debug( "entered - @_" );
    750852
    751853    my ( $key, $type ) = validate_pos( @_,
     
    764866    );
    765867
     868    my $sql = $self->sql;
     869
    766870    # ignore volume
    767     $key = parse_neb_key($key);
    768 
    769     my $log = $self->log;
    770     my $sql = $self->sql;
     871    eval {
     872        $key = parse_neb_key($key);
     873    };
     874    $log->logdie("$@") if $@;
     875
    771876    my $db  = $self->db($key);
    772 
    773     $log->debug( "entered - @_" );
    774877
    775878    my $so_id;
     
    785888                unless ( $rows == 1 ) {
    786889                    $query->finish;
    787                     $log->logdie( "storage object does not exist" );
     890                    die( "storage object does not exist" );
    788891                }
    789892
     
    800903                # can't set a write lock if there are read locks
    801904                if ($write_lock) {
    802                     $log->logdie("can not write lock twice -- retry");
     905                    die("can not write lock twice -- retry");
    803906                }
    804907               
    805908                if ($read_lock > 0) {
    806                     $log->logdie("can not write lock after read lock -- retry");
     909                    die("can not write lock after read lock -- retry");
    807910                }
    808911
     
    813916                    # if we affected more then one row something very bad has happened.
    814917                    unless ($rows == 1) {
    815                         $log->logdie("affected row count is $rows instead of 1");
     918                        die("affected row count is $rows instead of 1");
    816919                    }
    817920
     
    820923                # can't set a read lock if there's a write lock
    821924                if ($write_lock) {
    822                     $log->logdie("can not read lock after write lock -- retry");
     925                    die("can not read lock after write lock -- retry");
    823926                }
    824927
     
    829932                    # if we affected more then one row something very bad has happened.
    830933                    unless ($rows == 1) {
    831                         $log->logdie("affected row count is $rows instead of 1");
     934                        die("affected row count is $rows instead of 1");
    832935                    }
    833936                }
     
    840943            $db->rollback;
    841944            $log->debug("rollback");
    842             if ($@ =~ /Deadlock found/) {
    843                 $log->warn("database deadlock retrying transaction: $@");
     945            if ($@ =~ $trans_regex) {
     946                $log->warn("database error, retrying transaction: $@");
     947                sleep TRANS_RETRY_WAIT;
    844948                redo TRANS;
    845949            }
     
    858962{
    859963    my $self = shift;
     964
     965    my $log = $self->log;
     966    $log->debug( "entered - @_" );
    860967
    861968    my ( $key, $type ) = validate_pos( @_,
     
    874981    );
    875982
     983    my $sql = $self->sql;
     984
    876985    # ignore volume
    877     $key = parse_neb_key($key);
    878 
    879     my $log = $self->log;
    880     my $sql = $self->sql;
     986    eval {
     987        $key = parse_neb_key($key);
     988    };
     989    $log->logdie("$@") if $@;
     990
    881991    my $db  = $self->db($key);
    882 
    883     $log->debug( "entered - @_" );
    884992
    885993    my $so_id;
     
    8951003                unless ($rows == 1) {
    8961004                    $query->finish;
    897                     $log->logdie("storage object does not exist");
     1005                    die("storage object does not exist");
    8981006                }
    8991007
     
    9091017                # can't remove a write lock if it doesn't exist
    9101018                if ($read_lock) {
    911                     $log->logdie("can not have a write lock under a read lock");
     1019                    die("can not have a write lock under a read lock");
    9121020                }
    9131021
    9141022                unless ($write_lock) {
    915                     $log->logdie("can not remove non-existant write lock");
     1023                    die("can not remove non-existant write lock");
    9161024                }
    9171025
     
    9221030                    # if we affected more then one row something very bad has happened.
    9231031                    unless ($rows == 1) {
    924                         $log->logdie("affected row count is $rows instead of 1");
     1032                        die("affected row count is $rows instead of 1");
    9251033                    }
    9261034                }
     
    9291037                # can't remove a read lock if there aren't any
    9301038                if ($write_lock) {
    931                     $log->logdie("can not have a read lock under a write lock");
     1039                    die("can not have a read lock under a write lock");
    9321040                }
    9331041                   
    9341042                if ($read_lock == 0) {
    935                     $log->logdie("can not remove non-existant read lock");
     1043                    die("can not remove non-existant read lock");
    9361044                }
    9371045
     
    9421050                    # if we affected more then one row something very bad has happened.
    9431051                    unless ($rows == 1) {
    944                         $log->logdie("affected row count is $rows instead of 1");
     1052                        die("affected row count is $rows instead of 1");
    9451053                    }
    9461054
     
    9531061            $db->rollback;
    9541062            $log->debug("rollback");
    955             if ($@ =~ /Deadlock found/) {
    956                 $log->warn("database deadlock retrying transaction: $@");
     1063            if ($@ =~ $trans_regex) {
     1064                $log->warn("database error, retrying transaction: $@");
     1065                sleep TRANS_RETRY_WAIT;
    9571066                redo TRANS;
    9581067            }
     
    9711080{
    9721081    my $self = shift;
     1082
     1083    my $log = $self->log;
     1084    $log->debug("entered - @_");
    9731085
    9741086    my ($key, $name, $value, $flags) = validate_pos(@_,
     
    9811093        {
    9821094            type        => SCALAR,
     1095            callbacks   => {
     1096                'xattr is in user. namespace'
     1097                    => sub { ($_[0]) =~ qr/^user\./ },
     1098            },
    9831099        },
    9841100        {
     
    9931109    );
    9941110
     1111    my $sql = $self->sql;
     1112
    9951113    # ignore volume
    996     $key = parse_neb_key($key);
    997 
    998     my $log = $self->log;
    999     my $sql = $self->sql;
     1114    eval {
     1115        $key = parse_neb_key($key);
     1116    };
     1117    $log->logdie("$@") if $@;
     1118
    10001119    my $db  = $self->db($key);
    1001 
    1002     $log->debug("entered - @_");
    10031120
    10041121TRANS: while (1) {
     
    10201137            if ($flags eq 'create') {
    10211138                unless ($rows == 1) {
    1022                     $log->logdie( "affected row count is $rows instead of 1" );
     1139                    die( "affected row count is $rows instead of 1" );
    10231140                }
    10241141            } else {
     
    10261143                # the case of a replace and 1 if the xattr didn't already exist.
    10271144                unless ($rows == 1 or $rows == 2) {
    1028                     $log->logdie( "affected row count is $rows instead of 2" );
     1145                    die( "affected row count is $rows instead of 2" );
    10291146                }
    10301147            }
     
    10361153            $db->rollback;
    10371154            $log->debug("rollback");
    1038             if ($@ =~ /Deadlock found/) {
    1039                 $log->warn("database deadlock retrying transaction: $@");
     1155            if ($@ =~ $trans_regex) {
     1156                $log->warn("database error, retrying transaction: $@");
     1157                sleep TRANS_RETRY_WAIT;
    10401158                redo TRANS;
    10411159            }
     
    10541172{
    10551173    my $self = shift;
     1174
     1175    my $log = $self->log;
     1176    $log->debug("entered - @_");
    10561177
    10571178    my ($key, $name) = validate_pos(@_,
     
    10641185        {
    10651186            type        => SCALAR,
     1187            callbacks   => {
     1188                'xattr is in user. namespace'
     1189                    => sub { ($_[0]) =~ qr/^user\./ },
     1190            },
    10661191        },
    10671192    );
    10681193
     1194    my $sql = $self->sql;
     1195
    10691196    # ignore volume
    1070     $key = parse_neb_key($key);
    1071 
    1072     my $log = $self->log;
    1073     my $sql = $self->sql;
     1197    eval {
     1198        $key = parse_neb_key($key);
     1199    };
     1200    $log->logdie("$@") if $@;
     1201
    10741202    my $db  = $self->db($key);
    1075 
    1076     $log->debug("entered - @_");
    10771203
    10781204    my $value;
     
    10851211        if ($rows == 0) {
    10861212            $query->finish;
    1087             $log->logdie( "xattr $key:$name does not exist" );
     1213            die( "xattr $key:$name does not exist" );
    10881214        }
    10891215        # if we go more then one row bad something very bad has happened.
    10901216        unless ($rows == 1) {
    10911217            $query->finish;
    1092             $log->logdie( "affected row count is $rows instead of 1" );
     1218            die( "affected row count is $rows instead of 1" );
    10931219        }
    10941220
     
    10991225        $value = $row->{ 'value' };
    11001226    };
    1101     $log->logdie("database error: $@") if $@;
     1227    if ($@) {
     1228        if ($@ =~ /user\..*? does not exist/) {
     1229            # do not log xattr does not exist messages
     1230            die $@;
     1231        }
     1232        $log->logdie("database error: $@") if $@;
     1233    }
    11021234
    11031235    $log->debug("leaving");
     
    11101242{
    11111243    my $self = shift;
     1244
     1245    my $log = $self->log;
     1246    $log->debug("entered - @_");
    11121247
    11131248    my ($key) = validate_pos(@_,
     
    11201255    );
    11211256
     1257    my $sql = $self->sql;
     1258
    11221259    # ignore volume
    1123     $key = parse_neb_key($key);
    1124 
    1125     my $log = $self->log;
    1126     my $sql = $self->sql;
     1260    eval {
     1261        $key = parse_neb_key($key);
     1262    };
     1263    $log->logdie("$@") if $@;
     1264
    11271265    my $db  = $self->db($key);
    1128 
    1129     $log->debug("entered - @_");
    11301266
    11311267    my @xattrs;
     
    11511287    my $self = shift;
    11521288
     1289    my $log = $self->log;
     1290    $log->debug("entered - @_");
     1291
    11531292    my ($key, $name) = validate_pos(@_,
    11541293        {
     
    11601299        {
    11611300            type        => SCALAR,
     1301            callbacks   => {
     1302                'xattr is in user. namespace'
     1303                    => sub { ($_[0]) =~ qr/^user\./ },
     1304            },
    11621305        },
    11631306    );
    11641307
     1308    my $sql = $self->sql;
     1309
    11651310    # ignore volume
    1166     $key = parse_neb_key($key);
    1167 
    1168     my $log = $self->log;
    1169     my $sql = $self->sql;
     1311    eval {
     1312        $key = parse_neb_key($key);
     1313    };
     1314    $log->logdie("$@") if $@;
     1315
    11701316    my $db  = $self->db($key);
    1171 
    1172     $log->debug("entered - @_");
    11731317
    11741318TRANS: while (1) {
     
    11791323            $query->finish;
    11801324
     1325            # no rows affected means the xattr did not exist
     1326            if ($rows == 0) {
     1327                die( "xattr $key:$name does not exist" );
     1328            }
     1329
    11811330            # if we affected more then one row something very bad has happened.
    1182             unless ($rows == 1) {
    1183                 $log->logdie( "affected row count is $rows instead of 1" );
     1331            if ($rows > 1) {
     1332                die( "affected row count is $rows instead of 1" );
    11841333            }
    11851334
     
    11901339            $db->rollback;
    11911340            $log->debug("rollback");
    1192             if ($@ =~ /Deadlock found/) {
    1193                 $log->warn("database deadlock retrying transaction: $@");
     1341            if ($@ =~ $trans_regex) {
     1342                $log->warn("database error, retrying transaction: $@");
     1343                sleep TRANS_RETRY_WAIT;
    11941344                redo TRANS;
    11951345            }
     
    12091359    my $self = shift;
    12101360
     1361    my $log = $self->log;
     1362    $log->debug( "entered - @_" );
     1363
    12111364    my ($pattern) = validate_pos( @_,
    12121365        {
     
    12161369    );
    12171370
    1218     $pattern = parse_neb_key($pattern);
    1219 
    1220     my $log = $self->log;
    1221 
    1222     $log->debug( "entered - @_" );
     1371
     1372    eval {
     1373        $pattern = parse_neb_key($pattern) if defined $pattern;
     1374    };
     1375    $log->logdie("$@") if $@;
    12231376
    12241377    unless (defined $pattern) {
     
    12351388    $log->logdie("no keys found") unless ( scalar @keys );
    12361389
     1390    if (defined $self->cache) {
     1391        foreach my $path (@keys) {
     1392            $self->cache->set($path, 1);
     1393                $log->debug("key added to cache as: $path");
     1394        }
     1395    }
     1396
    12371397    $log->debug( "leaving" );
    12381398
     
    12451405
    12461406    my $self    = shift;
     1407
     1408    my $log = $self->log;
     1409    $log->debug( "entered - @_" );
     1410
    12471411    my $index   = shift;
    12481412    my $key     = shift;
    12491413
    1250     my $log = $self->log;
    12511414    my $sql = $self->sql;
    12521415    my $db  = $self->_db_for_index($index);
    12531416
    1254     $log->debug( "entered - @_" );
    12551417
    12561418    # first check to see if the key is an exact match
     
    13101472    my $self = shift;
    13111473
     1474    my $log = $self->log;
     1475    $log->debug("entered - @_");
     1476
    13121477    my ($key, $vol_name) = validate_pos(@_,
    13131478        {
     
    13301495    );
    13311496
     1497    my $sql = $self->sql;
     1498
     1499#    unless ($key) {
     1500#        $log->warn("key was undefined after validate_pos(), trying again...");
     1501#        return $self->find_instances(@_);
     1502#    }
     1503
    13321504    # vol_name overrides the key implied volume
    1333     $key = parse_neb_key($key, $vol_name);
     1505    eval {
     1506        $key = parse_neb_key($key, $vol_name);
     1507    };
     1508    $log->logdie("$@") if $@;
    13341509    $vol_name = $key->volume;
    13351510
    1336     my $log = $self->log;
    1337     my $sql = $self->sql;
    13381511    my $db  = $self->db($key);
    1339 
    1340     $log->debug("entered - @_");
    13411512
    13421513    # the key's volume can't be validiated on input for this method so we have
     
    13441515    if (defined $vol_name
    13451516        and not $self->_is_valid_volume_name($key, $key->volume)) {
    1346         if ($key->soft_volume) {
     1517        if ($key->hard_volume) {
     1518            $log->logdie("$vol_name is not a valid volume name");
     1519        } else {
    13471520            $log->warn( "$vol_name is not a known volume name" );
    13481521            $vol_name = undef;
    1349         } else {
    1350             die "$vol_name is not a valid volume name"
    13511522        }
    13521523    }
     
    13611532            unless ($rows > 0) {
    13621533                $query->finish;
    1363                 $log->logdie("no instances on storage volume or volume is not avaiable for key: $key volume: $vol_name");
     1534                die("no instances on storage volume or volume is not avaiable for key: $key volume: $vol_name");
    13641535            }
    13651536        } else {
     
    13691540            unless ($rows > 0) {
    13701541                $query->finish;
    1371                 $log->logdie("no instances available for key: $key");
     1542                die("no instances available for key: $key");
    13721543            }
    13731544        }
     
    13811552        $db->rollback;
    13821553        # handle soft volumes
    1383         if (defined $vol_name and defined $key->soft_volume) {
     1554        if (defined $vol_name and not defined $key->hard_volume) {
    13841555            $log->debug("retrying with 'any' volume");
    13851556            return $self->find_instances($key->path, 'any');
     
    14031574    my $self = shift;
    14041575
     1576    my $log = $self->log;
     1577    $log->debug( "entered - @_" );
     1578
    14051579    my ($key, $uri) = validate_pos( @_,
    14061580        {
     
    14151589    );
    14161590
     1591    my $sql = $self->sql;
     1592
    14171593    # ignore volume
    1418     $key = parse_neb_key($key);
    1419 
    1420     my $log = $self->log;
    1421     my $sql = $self->sql;
     1594    eval {
     1595        $key = parse_neb_key($key);
     1596    };
     1597    $log->logdie("$@") if $@;
     1598
    14221599    my $db  = $self->db($key);
    1423 
    1424     $log->debug( "entered - @_" );
    14251600
    14261601TRANS: while (1) {
    14271602        eval {
     1603            my $instances;
    14281604            my $so_id;
    1429             my $instances;
    1430             # get so_id
     1605            my $ins_id;
     1606            # find so_id for key and get count of instances
    14311607            {
    1432                 my $query = $db->prepare_cached( $sql->get_object_from_uri );
    1433                 my $rows = $query->execute( $uri );
    1434 
     1608                my $query = $db->prepare_cached( $sql->get_instance_count_by_ext_id );
     1609                my $rows = $query->execute($key->path);
    14351610                unless ( $rows > 0 ) {
    14361611                    $query->finish;
    1437                     $log->logdie( "no instance is associated with uri" );
    1438                 }
    1439 
    1440                 $so_id = $query->fetchrow_hashref->{ 'so_id' };
     1612                    die( "$key has no associated instances - this should not happen" );
     1613                }
     1614
     1615                my $record = $query->fetchrow_hashref;
     1616                $so_id      = $record->{ 'so_id' };
     1617                $instances  = $record->{ 'count(ins_id)' };
    14411618                $query->finish;
    1442 
    1443             }
    1444 
     1619            }
     1620
     1621            # find ins_id for uri
    14451622            {
    1446                 my $query = $db->prepare_cached( $sql->get_instance_count );
    1447                 $query->execute( $so_id );
    1448 
    1449                 $instances = $query->fetchrow_hashref->{ 'count(ins_id)' };
     1623                my $query = $db->prepare_cached( $sql->get_instance_by_uri );
     1624                my $rows = $query->execute($so_id, $uri);
     1625                unless ( $rows > 0) {
     1626                    $query->finish;
     1627                    die( "no instance is associated with uri" );
     1628                }
     1629
     1630                $ins_id = $query->fetchrow_hashref->{ 'ins_id' };
    14501631                $query->finish;
    14511632            }
     
    14531634            # remove instance
    14541635            {
    1455                 my $query = $db->prepare_cached( $sql->delete_instance );
    1456                 my $rows = $query->execute( $uri );
     1636                my $query = $db->prepare_cached( $sql->delete_instance_by_ins_id );
     1637                my $rows = $query->execute( $ins_id );
    14571638                $query->finish;
    14581639               
    1459                 # if we affected something other then two rows something very bad
    1460                 # has happened
     1640                # if we affected something other then one row something very
     1641                # bad has happened
    14611642                unless ( $rows == 1 ) {
    1462                     $log->logdie( "affected row count is $rows instead of 1" );
     1643                    die( "affected row count is $rows instead of 1" );
    14631644                }
    14641645            }
     
    14671648            # remove it too
    14681649            if ( $instances == 1 ) {
     1650                # remove key from cache
     1651                $self->cache->delete($key->path) if defined $self->cache;
     1652
    14691653                # we just removed the last instance
    14701654                my $query = $db->prepare_cached( $sql->delete_object );
     
    14741658                # TODO: this will have to be changed in order to support hardlinks
    14751659                unless ( $rows == 1 ) {
    1476                     $log->logdie( "affected row count is $rows instead of 2" );
     1660                    die( "affected row count is $rows instead of 2" );
    14771661                }
    14781662            }
     
    14841668            $db->rollback;
    14851669            $log->debug("rollback");
    1486             if ($@ =~ /Deadlock found/) {
    1487                 $log->warn("database deadlock retrying transaction: $@");
     1670            if ($@ =~ $trans_regex) {
     1671                $log->warn("database error, retrying transaction: $@");
     1672                sleep TRANS_RETRY_WAIT;
    14881673                redo TRANS;
    14891674            }
     
    15021687{
    15031688    my $self = shift;
     1689
     1690    my $log = $self->log;
     1691    $log->debug("entered - @_");
    15041692
    15051693    my ( $key ) = validate_pos( @_,
     
    15121700    );
    15131701
     1702    my $sql = $self->sql;
     1703
    15141704    # ignore volume
    1515     $key = parse_neb_key($key);
    1516 
    1517     my $log = $self->log;
    1518     my $sql = $self->sql;
     1705    eval {
     1706        $key = parse_neb_key($key);
     1707    };
     1708    $log->logdie("$@") if $@;
     1709
    15191710    my $db  = $self->db($key);
    1520 
    1521     $log->debug("entered - @_");
    15221711
    15231712    my $stat;
     
    15271716
    15281717        unless ($rows == 1) {
    1529             $log->logdie("no storage object found");
     1718            die("no storage object found");
    15301719        }
    15311720
     
    15481737    my $self = shift;
    15491738
     1739    my $log = $self->log;
     1740    $log->debug("entered - @_");
     1741
    15501742    validate_pos(@_);
    15511743
    1552     my $log = $self->log;
    15531744    my $sql = $self->sql;
    15541745    my $db  = $self->_db_for_index(0); # XXX fix as above
    15551746
    1556     $log->debug("entered - @_");
    1557 
    15581747    my $stats;
    15591748    my $query;
     
    15761765}
    15771766
     1767sub chmod_object
     1768{
     1769    my $self = shift;
     1770
     1771    my $log = $self->log;
     1772    $log->debug("entered - @_");
     1773
     1774    my ($key, $mode) = validate_pos( @_,
     1775        {
     1776            type        => SCALAR,
     1777            callbacks   => {
     1778                'is valid object key' => sub { $self->_is_valid_object_key($_[0]) },
     1779            },
     1780        },
     1781        {
     1782            type        => SCALAR,
     1783            regex       => qr/\d{3,4}/,
     1784            callbacks   => {
     1785                'is allowable mode' => sub {
     1786                    $_[0] == (S_IRUSR | S_IRGRP)
     1787                },
     1788            },
     1789        },
     1790    );
     1791
     1792    my $sql = $self->sql;
     1793
     1794    # ignore volume
     1795    eval {
     1796        $key = parse_neb_key($key);
     1797    };
     1798    $log->logdie("$@") if $@;
     1799
     1800    my $db  = $self->db($key);
     1801
     1802    # find all instances of this object
     1803    my $locations;
     1804    eval {
     1805        $locations = $self->find_instances("$key");
     1806    };
     1807    $log->logdie("error: $@") if $@;
     1808
     1809    # update each instances
     1810    foreach my $inst (@$locations) {
     1811        my $path = URI->new($inst)->path;
     1812
     1813        $self->_retry(sub { chmod($mode, $path) })
     1814            or $log->logdie("can not chmod() $path: $!");
     1815
     1816        # XXX I'm assuming that it's OK to fsync() a filehandle that's only
     1817        # open for reading?  Opening as w/rw here can fail if the chmod removes
     1818        # write permissions.
     1819        my $fh;
     1820        $self->_retry(sub { open($fh, '<', $path) })
     1821            or $log->logdie("can not open() $path: $!");
     1822
     1823        # fsync(3c)
     1824        $self->_retry(sub { $fh->sync() })
     1825            or $log->logdie("can not sync() $path: $!");
     1826
     1827        $self->_retry(sub { close($fh) })
     1828            or $log->logdie("can not close() $path: $!");
     1829    }
     1830
     1831    # stick an xattr on this object with the mode
     1832    # XXX this would probably be better as a field in the storage_object_attr
     1833    # table but since we're not planning to use this for very many objects (as
     1834    # a %) it may not be worth adding the extra field at this time.
     1835    eval {
     1836        $self->setxattr_object("$key", 'user.mode', $mode, 'replace');
     1837    };
     1838    $log->logdie("error: $@") if $@;
     1839
     1840    $log->debug("leaving");
     1841
     1842    return $mode;
     1843}
    15781844
    15791845sub _get_storage_volume
     
    15811847    my $self = shift;
    15821848
    1583     my ($key, $name, $soft_volume) = @_;
    1584 
    1585     my $log = $self->log;
    1586     my $sql = $self->sql;
    1587     my $db  = $self->db($key);
    1588 
     1849    my $log = $self->log;
    15891850    no warnings qw( uninitialized );
    15901851    $log->debug( "entered - @_" );
    15911852    use warnings;
     1853
     1854    my ($key, $name, $hard_volume) = @_;
     1855
     1856    my $sql = $self->sql;
     1857    my $db  = $self->db($key);
    15921858
    15931859    my ($vol_id, $vol_host, $vol_path, $xattr);
     
    16051871                # if a volume name was specified, and is soft, and we failed to
    16061872                # find it, fall back to any volume
    1607                 if ($soft_volume) {
     1873                unless ($hard_volume) {
    16081874                    ($vol_id, $vol_host, $vol_path, $xattr) = $self->_get_storage_volume($key);
    16091875                    return; # this just returns out of the eval not from the subroutine
    16101876                }
    1611                 $log->logdie("storage volume: $name is not available");
     1877                die("storage volume: $name is not available");
    16121878            }
    16131879            # when matching by name we shouldn't ever match more than once
    16141880            if ($rows > 1) {
    16151881                $query->finish;
    1616                 $log->logdie("affected row count is $rows instead of 1");
     1882                die("affected row count is $rows instead of 1");
    16171883            }
    16181884        } else {
     
    16231889            unless ($rows > 0) {
    16241890                $query->finish;
    1625                 $log->logdie("no storage volume is available");
     1891                die("no storage volume is available for key: $key volume: $name hard_volume: $hard_volume");
    16261892            }
    16271893        }
     
    16311897        $query->finish;
    16321898    };
    1633     $log->logdie("database error: $@") if $@;
     1899    if ($@) {
     1900        if ($@ =~ qr/no storage volume is available/) {
     1901            # this should not happen unless all volumes are full
     1902            $log->error($@);
     1903            $log->debug("retrying...");
     1904            return $self->_get_storage_volume(@_);
     1905        }
     1906        # else
     1907        $log->logdie("database error: $@");
     1908    }
    16341909
    16351910    $log->logdie("failed to find a suitable volume" )
     
    16461921    my $self = shift;
    16471922
    1648     my $key = shift;
    1649 
    1650     my $log = $self->log;
    1651     my $sql = $self->sql;
    1652     my $db  = $self->db($key);
    1653 
     1923    my $log = $self->log;
    16541924    no warnings qw( uninitialized );
    16551925    $log->debug( "entered - @_" );
    16561926    use warnings;
     1927
     1928    my $key = shift;
     1929
     1930    my $sql = $self->sql;
     1931    my $db  = $self->db($key);
    16571932
    16581933    my ($vol_id, $vol_host, $vol_path, $xattr);
     
    16651940        unless ($rows > 0) {
    16661941            $query->finish;
    1667             $log->logdie("can't find a suitable storage volume to replicate $key to");
     1942            die("can't find a suitable storage volume to replicate $key to");
    16681943        }
    16691944        # when matching by name we shouldn't ever match more than once
    16701945        if ($rows > 1) {
    16711946            $query->finish;
    1672             $log->logdie("affected row count is $rows instead of 1");
     1947            die("affected row count is $rows instead of 1");
    16731948        }
    16741949
     
    16901965sub _is_valid_object_key
    16911966{
    1692     my ($self, $key) = @_;
    1693 
    1694     $key = parse_neb_key($key);
    1695 
    1696     my $log = $self->log;
     1967    my $self = shift;
     1968
     1969    my $log = $self->log;
     1970    $log->debug( "entered - @_" );
     1971
     1972    my ($key) = @_;
     1973
    16971974    my $sql = $self->sql;
     1975
     1976    eval {
     1977        $key = parse_neb_key($key);
     1978    };
     1979    $log->logdie("$@") if $@;
     1980
     1981    # check cache first
     1982    my $cached = $self->cache->get($key->path) if defined $self->cache;
     1983    if (defined $cached) {
     1984        $log->debug( "key $key found in cache as ", $key->path );
     1985        $log->debug( "leaving" );
     1986        return 1;
     1987    } else {
     1988        $log->debug( "key $key not found in cache" );
     1989    }
     1990
    16981991    my $db  = $self->db($key);
    16991992
     
    17122005
    17132006    if (defined $ext_id) {
     2007        $log->debug( "key found in db" );
     2008        # add key to cache
     2009        $self->cache->set($key->path, 1) if defined $self->cache;
     2010        $log->debug( "key added to cache as ", $key->path );
     2011        $log->debug( "leaving" );
    17142012        return 1;
    17152013    }
    17162014
     2015    $log->debug( "key not found in db" );
     2016    $log->debug( "leaving" );
     2017
    17172018    return;
    17182019}
     
    17212022sub _is_valid_volume_name
    17222023{
    1723     my ($self, $key, $vol_name) = @_;
    1724 
    1725     $key = parse_neb_key($key);
     2024    my $self = shift;
     2025
     2026    my $log = $self->log;
     2027    $log->debug( "entered - @_" );
     2028
     2029    my ($key, $vol_name) = @_;
     2030
     2031    my $sql = $self->sql;
     2032
     2033    # the volume name implied by the key is ignored.  $key is only needed to
     2034    # select a database connection
     2035    eval {
     2036        $key = parse_neb_key($key);
     2037    };
     2038    $log->logdie("$@") if $@;
    17262039    my $volume_info = parse_neb_volume($vol_name);
    17272040
    1728     my $log = $self->log;
    1729     my $sql = $self->sql;
    17302041    my $db  = $self->db($key);
    17312042
     
    17342045    # handle "any" volume
    17352046    if ($vol_name eq 'any') {
     2047        $log->debug( "found volume name $vol_name" );
     2048        $log->debug( "leaving" );
    17362049        return 1;
    17372050    }
     
    17482061
    17492062    if (defined $vol_id and defined $vol_path) {
     2063        $log->debug( "found volume name $vol_name" );
     2064        $log->debug( "leaving" );
    17502065        return 1;
    17512066    }
    17522067
     2068    $log->debug( "volume name $vol_name not found" );
     2069    $log->debug( "leaving" );
     2070
    17532071    return;
    17542072}
     
    17592077    my $self = shift;
    17602078
     2079    my $log = $self->log;
     2080    $log->debug( "entered - @_" );
     2081
    17612082    my ($key, $so_id, $ins_id, $vol_path, $xattr) =  @_;
    17622083
    1763     my $log = $self->log;
    17642084    my $sql = $self->sql;
    17652085    my $db  = $self->db($key);
     
    17702090        my $storage_filename = $self->_generate_storage_filename($key->path, $ins_id);
    17712091        unless (-d $storage_path) {
    1772             _retry(sub { mkpath(@_) }, $storage_path, 0, 0775)
    1773                 or die "can't create storage path: $storage_path";
     2092            $self->_retry(sub { mkpath([$storage_path], 0, 0775) })
     2093                or die("can't create storage path: $storage_path");
    17742094        }
    17752095        # check to make sure at least the parent directory has the proper
    17762096        # permissions
    1777         my $mode = [_retry(sub { stat($storage_path) } )]->[2] & 07777;
     2097        my $mode = [$self->_retry(sub { stat($storage_path) } )]->[2] & 07777;
    17782098        unless ($mode == 0775) {
    1779             $log->error("$storage_path has the wrong permissions of: %04x", $mode);
    1780             _retry(sub { chmod(0775, $storage_path) }) or die "can't chmod $storage_path: $!";
     2099            # XXX: this problem is so common that it's flooding the logs
     2100            $log->debug("$storage_path has the wrong permissions of: 0", sprintf("%o", $mode));
     2101            $self->_retry(sub { chmod(0775, $storage_path) })
     2102                or die("can not chmod() $storage_path: $!");
    17812103        }
    17822104
     
    17872109    };
    17882110    if ($@) {
     2111        if (defined $uri and -e $uri->file) {
     2112            unlink($uri->file)
     2113                or $log->error("failed to unlink() $uri: $!");
     2114        }
    17892115        $log->logdie($@);
    17902116    }
     
    17922118    if ($xattr) {
    17932119        my $path = $uri->file;
    1794         die "can not set xattr on $path: $!"
     2120        $log->logdie("can not set xattr on $path: $!")
    17952121            unless (setfattr($path, 'user.nebulous_key', $key->path));
    17962122    }
     
    18042130    my $self = shift;
    18052131
     2132    my $log = $self->log;
     2133    $log->debug( "entered - @_" );
     2134
    18062135    my ($path) = @_;
    18072136
    18082137    # perl's open() can't do an O_CREAT | O_EXCL
    1809     die "file $path already exists" if (-e $path);
     2138    # XXX is it possible to tell if this system call failed?
     2139    -e $path
     2140        and $log->logdie("file $path already exists");
    18102141
    18112142    my $fh;
    1812     die "can not open $path: $!"
    1813         unless (_retry(sub { open($fh, '>', $path) }));
     2143    $self->_retry(sub { open($fh, '>', $path) })
     2144        or $log->logdie("can not open() $path: $!");
    18142145
    18152146    # chmod before fsync() to make sure the changed perms hit the disk too
    1816     die "can not chmod $path: $!"
    1817         unless (_retry(sub { chmod(0664, $path) }));
    1818 
    1819     die "can not flush $path: $!"
    1820         unless ($fh->flush);
    1821 
    1822     die "can not sync $path: $!"
    1823         unless ($fh->sync);
    1824 
    1825     die "can not close $path: $!"
    1826         unless (_retry(sub { close($fh) }));
     2147    $self->_retry(sub { chmod(0664, $path) })
     2148        or $log->logdie("can not chmod() $path: $!");
     2149
     2150    $self->_retry(sub { $fh->sync() })
     2151        or $log->logdie("can not sync() $path: $!");
     2152
     2153    $self->_retry(sub { close($fh) })
     2154        or $log->logdie("can not close() $path: $!");
    18272155
    18282156    return $path;
     
    18612189sub _retry
    18622190{
     2191    my $self = shift;
     2192
     2193    my $log = $self->log;
     2194    $log->debug( "entered - @_" );
     2195
    18632196    my $func = shift;
    18642197
     
    18692202        };
    18702203        if ($@) {
    1871             die $@;
    1872             sleep 1;
     2204            $log->logdie($@);
     2205            sleep NFS_RETRY_WAIT;
    18732206            next;
    18742207        }
     
    18792212    # if the loop ended and $@ is set, rethrow the error
    18802213    if ($@) {
    1881         die $@;
     2214        $log->logdie($@);
    18822215    }
    18832216
  • branches/eam_branches/20090522/Nebulous-Server/lib/Nebulous/Server.pod

    r23932 r24557  
    2929    Nebulous::Server->stat_object( $key );
    3030    Nebulous::Server->mounts();
     31    Nebulous::Server->chmod_object( $key, $mode) ;
    3132
    3233=head1 DESCRIPTION
     
    203204    ]
    204205
     206=item * chmod_object( $key, $mode );
     207
     208Accepts 2 parameters, both mandatory.  C<$key> is the nebulous key to operate
     209on and C<$mode> are the POSIX like file permissions to set on all instances of
     210C<$key>.  C<$mode> must be specified in oct.  Returns C<$mode> or sucess or an
     211exception on failure.
     212
    205213=back
    206214
     
    223231=head1 COPYRIGHT
    224232
    225 Copyright (C) 2004-2008  Joshua Hoblitt.  All rights reserved.
     233Copyright (C) 2004-2009  Joshua Hoblitt.  All rights reserved.
    226234
    227235This program is free software; you can redistribute it and/or modify it under
  • branches/eam_branches/20090522/Nebulous-Server/lib/Nebulous/Server/Config.pm

    r23932 r24557  
    1313
    1414use Log::Log4perl qw( :levels );
    15 use Params::Validate qw( validate validate_pos SCALAR );
     15use Params::Validate qw( validate validate_pos SCALAR ARRAYREF );
    1616
    1717our %LEVELS = (
     
    4646        },
    4747    },
    48     dsn         => { type => SCALAR, optional => 1 },
    49     dbuser      => { type => SCALAR, optional => 1 },
    50     dbpasswd    => { type => SCALAR, optional => 1 },
     48    dsn                 => { type => SCALAR, optional => 1 },
     49    dbuser              => { type => SCALAR, optional => 1 },
     50    dbpasswd            => { type => SCALAR, optional => 1 },
     51    memcached_servers   => { type => ARRAYREF, optional => 1 },
    5152};
    5253
     
    6162
    6263    # normalize log levels to lower-case
    63     my $self = { trace => $LEVELS{lc($p{trace})} };
     64    my $self = {
     65        trace             => $LEVELS{lc($p{trace})},
     66        memcached_servers => $p{memcached_servers},
     67    };
    6468
    6569    bless $self, $class || ref $class;
  • branches/eam_branches/20090522/Nebulous-Server/lib/Nebulous/Server/SQL.pm

    r23947 r24557  
    175175        WHERE ext_id = ?
    176176    },
    177     delete_instance    => qq{
     177    delete_instance_by_ins_id => qq{
    178178        DELETE FROM instance
    179         WHERE uri = ?
     179        WHERE ins_id = ?
    180180    },
    181181    get_object_from_uri   => qq{
     
    184184        WHERE uri = ?
    185185    },
     186    get_instance_by_uri   => qq{
     187        SELECT ins_id
     188        FROM instance
     189        WHERE
     190            so_id = ?
     191            AND uri = ?
     192    },
    186193    get_instance_count   => qq{
    187194        SELECT count(ins_id)
    188195        FROM instance
    189196        WHERE so_id = ?
     197    },
     198    get_instance_count_by_ext_id   => qq{
     199        SELECT count(ins_id), so_id
     200        FROM instance
     201        JOIN storage_object
     202            USING(so_id)
     203        WHERE
     204            ext_id = ?
     205        GROUP BY so_id
    190206    },
    191207    get_object_instances    => qq{
     
    233249    get_replication_volume_for_ext_id   => qq{
    234250        SELECT
    235             vol_id,
     251            m.vol_id,
    236252            host,
    237253            path,
    238254            xattr,
    239255            total - used as free
    240         FROM (
    241 -- This query works but is slow...
    242 --             SELECT
    243 --                  mountedvol.*
    244 --             FROM mountedvol
    245 --             WHERE
    246 --                 vol_id NOT IN(
    247 --                     SELECT vol_id
    248 --                     FROM storage_object
    249 --                     JOIN instance
    250 --                         USING(so_id)
    251 --                     WHERE ext_id = --
    252 --                  )
    253                 SELECT
    254                     m.*
    255                 FROM mountedvol AS m
    256                 LEFT JOIN instance AS i
    257                     ON m.vol_id = i.vol_id
    258                     AND i.so_id = (
    259                         SELECT so_id
    260                         FROM storage_object
    261                         WHERE ext_id = ?
    262                     )
    263                 WHERE
    264                     i.vol_id IS NULL
    265         ) as Foo
     256        FROM mountedvol AS m
     257        LEFT JOIN instance AS i
     258            ON m.vol_id = i.vol_id
     259            AND i.so_id = (
     260                SELECT so_id
     261                FROM storage_object
     262                WHERE ext_id = ?
     263            )
    266264        WHERE
    267             used / total < ?
     265            i.vol_id IS NULL
     266            AND used / total < ?
    268267            AND available = ?
    269268            AND allocate = ?
    270         ORDER BY RAND()
    271         LIMIT 1
     269            ORDER BY RAND()
     270            LIMIT 1
    272271    },
    273272    get_storage_volume          => qq{
     
    287286    },
    288287    new_volume          => qq{
    289         INSERT INTO volume (name, host, path, allocate, available, xattr)
    290         VALUES (?, ?, ?, TRUE, TRUE, FALSE)
     288        INSERT INTO volume (name, host, path, allocate, available, xattr, mountpoint)
     289        VALUES (?, ?, ?, TRUE, TRUE, FALSE, ?)
    291290    },
    292291    get_volume_by_name => qq{
     
    397396    },
    398397    get_mounted_volumes => qq{
    399         SELECT * FROM mountedvol ORDER BY host, name
     398        SELECT mountpoint, total, used, vol_id, name, host, path, allocate, available, xattr FROM mountedvol ORDER BY host, name
    400399    },
    401400);
     
    424423DROP TABLE IF EXISTS lock_record;
    425424DROP TABLE IF EXISTS volume;
    426 DROP TABLE IF EXISTS mount;
     425DROP TABLE IF EXISTS mountedvol;
    427426DROP TABLE IF EXISTS log;
    428 DROP TABLE IF EXISTS mountedvol;
    429427DROP TABLE IF EXISTS directory;
    430428DROP PROCEDURE IF EXISTS getmountedvol;
     
    455453    FOREIGN KEY(parent_id) REFERENCES directory(dir_id),
    456454    PRIMARY KEY(dir_id),
    457     KEY(parent_id)
     455    KEY(parent_id),
     456    KEY(dirname),
     457    UNIQUE(dirname, parent_id)
    458458) ENGINE=innodb DEFAULT CHARSET=latin1;
    459459
     
    466466CREATE TABLE storage_object (
    467467    so_id BIGINT NOT NULL AUTO_INCREMENT,
    468     ext_id VARCHAR(255) NOT NULL UNIQUE,
     468    ext_id VARCHAR(255) NOT NULL,
    469469    ext_id_basename VARCHAR(255) NOT NULL,
    470470    dir_id BIGINT NOT NULL,
     
    472472    type enum('REG_FILE'),
    473473    PRIMARY KEY(so_id),
     474    UNIQUE KEY(ext_id),
    474475    KEY(dir_id),
    475476    KEY(type)
     
    514515CREATE TABLE volume (
    515516    vol_id INT NOT NULL AUTO_INCREMENT,
    516     name VARCHAR(255) UNIQUE NOT NULL,
     517    name VARCHAR(255) NOT NULL,
    517518    host VARCHAR(255) NOT NULL,
    518519    path VARCHAR(255) NOT NULL,
     
    520521    available BOOLEAN DEFAULT FALSE,
    521522    xattr BOOLEAN DEFAULT FALSE,
     523    mountpoint VARCHAR(255) NOT NULL,
    522524    PRIMARY KEY(vol_id),
     525    UNIQUE KEY(name),
     526    UNiQUE KEY(path),
    523527    KEY(host(16)),
    524     KEY(path(255)),
    525528    KEY(allocate),
    526     KEY(available)
     529    KEY(available),
     530    KEY(mountpoint(255))
     531) ENGINE=innodb DEFAULT CHARSET=latin1;
     532
     533###
     534
     535CREATE TABLE mountedvol(
     536    vol_id INT NOT NULL,
     537    FOREIGN KEY(vol_id) REFERENCES volume(vol_id) ON DELETE CASCADE,
     538    name VARCHAR(255) NOT NULL,
     539    host VARCHAR(255) NOT NULL,
     540    path VARCHAR(255) NOT NULL,
     541    FOREIGN KEY(path) REFERENCES volume(path) ON DELETE CASCADE,
     542    allocate BOOLEAN DEFAULT FALSE,
     543    available BOOLEAN DEFAULT FALSE,
     544    xattr BOOLEAN DEFAULT FALSE,
     545    mountpoint VARCHAR(255) NOT NULL,
     546    FOREIGN KEY(mountpoint) REFERENCES volume(mountpoint) ON DELETE CASCADE,
     547    total BIGINT NOT NULL,
     548    used BIGINT NOT NULL,
     549    PRIMARY KEY(vol_id),
     550    KEY(name),
     551    KEY(host),
     552    KEY(path),
     553    KEY(allocate),
     554    KEY(available),
     555    KEY(xattr),
     556    KEY(mountpoint(255))
    527557) ENGINE=innodb DEFAULT CHARSET=latin1;
    528558
     
    546576###
    547577
    548 CREATE TABLE mount (
    549     mountpoint VARCHAR(255) NOT NULL,
    550     total BIGINT NOT NULL,
    551     used BIGINT NOT NULL,
    552     PRIMARY KEY(mountpoint)
    553 ) ENGINE=innodb DEFAULT CHARSET=latin1;
    554 
    555 ###
    556 
    557578CREATE TABLE log (
    558579    timestamp TIMESTAMP,
     
    562583    message VARCHAR(2048) NOT NULL,
    563584    PRIMARY KEY(timestamp)
    564 ) ENGINE=innodb DEFAULT CHARSET=latin1;
    565 
    566 ###
    567 
    568 CREATE TABLE mountedvol(
    569     mountpoint VARCHAR(255) NOT NULL,
    570     FOREIGN KEY(mountpoint) REFERENCES mount(mountpoint) ON DELETE CASCADE,
    571     total BIGINT NOT NULL,
    572     used BIGINT NOT NULL,
    573     vol_id INT NOT NULL,
    574     FOREIGN KEY(vol_id) REFERENCES volume(vol_id) ON DELETE CASCADE,
    575     name VARCHAR(255) NOT NULL,
    576     host VARCHAR(255) NOT NULL,
    577     path VARCHAR(255) NOT NULL,
    578     FOREIGN KEY(path) REFERENCES volume(path) ON DELETE CASCADE,
    579     allocate BOOLEAN DEFAULT FALSE,
    580     available BOOLEAN DEFAULT FALSE,
    581     xattr BOOLEAN DEFAULT FALSE,
    582     PRIMARY KEY(mountpoint),
    583     KEY(vol_id),
    584     KEY(name),
    585     KEY(host),
    586     KEY(path),
    587     KEY(allocate),
    588     KEY(available),
    589     KEY(xattr)
    590585) ENGINE=innodb DEFAULT CHARSET=latin1;
    591586
     
    608603
    609604    -- store the okey checking state
    610     SELECT @@FOREIGN_KEY_CHECKS INTO key_checks;
     605--    SELECT @@FOREIGN_KEY_CHECKS INTO key_checks;
    611606    -- disable foregin check checks to prevent deadlocks on the mountedvol table
    612     SET FOREIGN_KEY_CHECKS=0;
     607--    SET FOREIGN_KEY_CHECKS=0;
    613608
    614609    -- make sure the temp table does not already exist... this can happy if the
     
    629624    OPEN cur1;
    630625
    631     DELETE FROM mountedvol;
    632 
    633626    myloop: LOOP
    634627        FETCH cur1 INTO vol_idvar, namevar, hostvar, pathvar, allocatevar, availablevar, xattrvar;
    635628        IF `done` THEN LEAVE myloop; END IF;
    636         INSERT INTO mountedvol
     629        REPLACE INTO mountedvol
    637630            SELECT mountpoint, total, used, vol_idvar, namevar, hostvar, pathvar, allocatevar, availablevar, xattrvar
    638631            FROM
     
    650643
    651644    -- restore the original key checking state
    652     SET @@FOREIGN_KEY_CHECKS = key_checks;
     645--    SET @@FOREIGN_KEY_CHECKS = key_checks;
    653646
    654647    DROP TABLE IF EXISTS myvolume;
    655648
    656     SET FOREIGN_KEY_CHECKS=1;
     649--    SET FOREIGN_KEY_CHECKS=1;
    657650
    658651    COMMIT;
  • branches/eam_branches/20090522/Nebulous-Server/lib/Test/Nebulous.pm

    r19493 r24557  
    1111use base qw( Exporter );
    1212
     13use Cache::Memcached;
    1314use DBI;
    1415use File::Path qw( mkpath rmtree );
     
    1617use Nebulous::Server::SQL;
    1718
    18 our @EXPORT = qw( $NEB_DB $NEB_USER $NEB_PASS );
     19our @EXPORT = qw( $NEB_DB $NEB_USER $NEB_PASS $NEB_MEMCACHED_SERVERS);
    1920
    2021our $NEB_DB     = $ENV{'NEB_DB'}   || "DBI:mysql:database=test:host=localhost";
    2122our $NEB_USER   = $ENV{'NEB_USER'} || "test";
    2223our $NEB_PASS   = $ENV{'NEB_PASS'} || '';
     24our $NEB_MEMCACHED_SERVERS = ['127.0.0.1:11211'];
    2325
    2426my $dbh = DBI->connect( $NEB_DB, $NEB_USER, $NEB_PASS );
     
    5355
    5456    # node01/node02: allocate = TRUE
    55     $dbh->do(qq{ INSERT INTO volume (vol_id, name, host, path, allocate, available) VALUES (1, 'node01', 'node01', ?, TRUE, TRUE) }, undef, $dir1);
    56     $dbh->do(qq{ INSERT INTO mount VALUES (?, 10e10, 10e7) }, undef, $dir1);
     57    $dbh->do(qq{ INSERT INTO volume (vol_id, name, host, path, mountpoint, allocate, available) VALUES (1, 'node01', 'node01', ?, '/', TRUE, TRUE) }, undef, $dir1);
     58    $dbh->do(qq{ INSERT INTO mountedvol SELECT *, 10e10, 10e7 FROM volume WHERE vol_id = ? }, undef, 1);
     59#    $dbh->do(qq{ INSERT INTO mount VALUES (?, 10e10, 10e7) }, undef, $dir1);
    5760
    58     $dbh->do(qq{ INSERT INTO volume (vol_id, name, host, path, allocate, available) VALUES (2, 'node02', 'node02', ?, TRUE, TRUE) }, undef, $dir2);
    59     $dbh->do(qq{ INSERT INTO mount VALUES (?, 10e10, 10e8) }, undef, $dir2);
     61    $dbh->do(qq{ INSERT INTO volume (vol_id, name, host, path, mountpoint, allocate, available) VALUES (2, 'node02', 'node02', ?, '/', TRUE, TRUE) }, undef, $dir2);
     62    $dbh->do(qq{ INSERT INTO mountedvol SELECT *, 10e10, 10e8 FROM volume WHERE vol_id = ? }, undef, 2);
     63#    $dbh->do(qq{ INSERT INTO mount VALUES (?, 10e10, 10e8) }, undef, $dir2);
    6064
    6165    # node03: allocate = TRUE
    62     $dbh->do(qq{ INSERT INTO volume (vol_id, name, host, path, allocate, available) VALUES (3, 'node03', 'node03', ?, TRUE, TRUE) }, undef, $dir3);
    63     $dbh->do(qq{ INSERT INTO mount VALUES (?, 10e10, 10e8) }, undef, $dir3);
     66    $dbh->do(qq{ INSERT INTO volume (vol_id, name, host, path, mountpoint, allocate, available) VALUES (3, 'node03', 'node03', ?, '/', TRUE, TRUE) }, undef, $dir3);
     67    $dbh->do(qq{ INSERT INTO mountedvol SELECT *, 10e10, 10e8 FROM volume WHERE vol_id = ? }, undef, 3);
     68#    $dbh->do(qq{ INSERT INTO mount VALUES (?, 10e10, 10e8) }, undef, $dir3);
    6469
    6570    # node04: allocate = FALSE, available = FALSE
    66     $dbh->do(qq{ INSERT INTO volume (vol_id, name, host, path, allocate, available) VALUES (4, 'node04', 'node04', ?, FALSE, FALSE) }, undef, $dir4);
    67     $dbh->do(qq{ INSERT INTO mount VALUES (?, 10e10, 10e7) }, undef, $dir4);
     71    $dbh->do(qq{ INSERT INTO volume (vol_id, name, host, path, mountpoint, allocate, available) VALUES (4, 'node04', 'node04', ?, '/', FALSE, FALSE) }, undef, $dir4);
     72    $dbh->do(qq{ INSERT INTO mountedvol SELECT *, 10e10, 10e7 FROM volume WHERE vol_id = ? }, undef, 4);
     73#    $dbh->do(qq{ INSERT INTO mount VALUES (?, 10e10, 10e7) }, undef, $dir4);
    6874
    6975    # node05: allocate = FALSE, available = TRUE
    70     $dbh->do(qq{ INSERT INTO volume (vol_id, name, host, path, allocate, available) VALUES (5, 'node05', 'node05', ?, FALSE, TRUE) }, undef, $dir5);
    71     $dbh->do(qq{ INSERT INTO mount VALUES (?, 10e10, 10e7) }, undef, $dir5);
     76    $dbh->do(qq{ INSERT INTO volume (vol_id, name, host, path, mountpoint, allocate, available) VALUES (5, 'node05', 'node05', ?, '/', FALSE, TRUE) }, undef, $dir5);
     77    $dbh->do(qq{ INSERT INTO mountedvol SELECT *, 10e10, 10e7 FROM volume WHERE vol_id = ? }, undef, 5);
     78#    $dbh->do(qq{ INSERT INTO mount VALUES (?, 10e10, 10e7) }, undef, $dir5);
    7279
    7380    # node06: allocate = TRUE, available = FALSE
    74     $dbh->do(qq{ INSERT INTO volume (vol_id, name, host, path, allocate, available) VALUES (6, 'node06', 'node06', ?, TRUE, FALSE) }, undef, $dir6);
    75     $dbh->do(qq{ INSERT INTO mount VALUES (?, 10e10, 10e7) }, undef, $dir6);
     81    $dbh->do(qq{ INSERT INTO volume (vol_id, name, host, path, mountpoint, allocate, available) VALUES (6, 'node06', 'node06', ?, '/', TRUE, FALSE) }, undef, $dir6);
     82    $dbh->do(qq{ INSERT INTO mountedvol SELECT *, 10e10, 10e7 FROM volume WHERE vol_id = ? }, undef, 6);
     83#    $dbh->do(qq{ INSERT INTO mount VALUES (?, 10e10, 10e7) }, undef, $dir6);
    7684
    7785    # node07: full
    78     $dbh->do(qq{ INSERT INTO volume (vol_id, name, host, path, allocate, available) VALUES (7, 'node07', 'node07', ?, TRUE, TRUE) }, undef, $dir7);
    79     $dbh->do(qq{ INSERT INTO mount VALUES (?, 10e10, 10e10) }, undef, $dir7);
     86    $dbh->do(qq{ INSERT INTO volume (vol_id, name, host, path, mountpoint, allocate, available) VALUES (7, 'node07', 'node07', ?, '/', TRUE, TRUE) }, undef, $dir7);
     87    $dbh->do(qq{ INSERT INTO mountedvol SELECT *, 10e10, 10e10 FROM volume WHERE vol_id = ? }, undef, 7);
     88#    $dbh->do(qq{ INSERT INTO mount VALUES (?, 10e10, 10e10) }, undef, $dir7);
    8089
    81     $dbh->do(qq{ call getmountedvol() });
     90#    $dbh->do(qq{ call getmountedvol() });
    8291}
    8392
    8493sub cleanup {
     94    # memcached needs to be emptied between test runs
     95        Cache::Memcached->new(servers => $NEB_MEMCACHED_SERVERS)->flush_all;
     96    # if flush_all() turns out to be useless as feared
     97#   my $memd = Cache::Memcached->new(servers => $NEB_MEMCACHED_SERVERS);
     98#   my $query = $dbh->prepare("SELECT ext_id FROM storage_object");
     99#   if ($query->execute) {
     100#        while (my $row = $query->fetchrow_hashref) {
     101#            my $ext_id = $row->{ext_id};
     102#            warn "found key $ext_id\n" if $memd->get($ext_id);
     103#            warn "deleted $ext_id\n" if $memd->delete($ext_id);
     104#        }
     105#   }
     106#   $query->finish;
     107
    85108    foreach my $statement (@{ $sql->get_db_clear }) {
    86109        $dbh->do( $statement );
  • branches/eam_branches/20090522/Nebulous-Server/scripts/dirize.pl

    r23952 r24557  
    11#!/usr/bin/env perl
     2
     3# query to check for duplicate directory entries
     4# select count(*) from (select so.so_id, so.ext_id, so.dir_id from storage_object as so join (select dir_id, dirname, parent_id, count(*) from directory group by dirname, parent_id  having count(*) > 1) as foo on so.dir_id = foo.dir_id) as foo;
    25
    36use strict;
     
    2326my $db = $neb->_db_for_index(0);
    2427
    25 my $n;
    26 {
    27     my $query = $db->prepare("SELECT COUNT(*) as n FROM storage_object");
    28     $query->execute;
    29     $n = $query->fetchrow_hashref->{'n'};
    30 }
     28my $n = 0;
     29#{
     30#    my $query = $db->prepare("SELECT COUNT(*) as n FROM storage_object");
     31#    $query->execute;
     32#    $n = $query->fetchrow_hashref->{'n'};
     33#}
    3134
    32 my $query = $db->prepare_cached("SELECT so_id, ext_id, dir_id FROM storage_object AS so WHERE so.dir_id = 0 LIMIT 1000");
     35# repair directory duplication
     36#my $query = $db->prepare_cached("select so.so_id, so.ext_id, so.dir_id from storage_object as so join (select dir_id, dirname, parent_id, count(*) from directory group by dirname, parent_id  having count(*) > 1) as foo on so.dir_id = foo.dir_id limit 1000");
     37
     38# initial directory fill in
     39my $work_query = $db->prepare_cached("SELECT so_id, ext_id, dir_id FROM storage_object AS so WHERE so.dir_id = 0 LIMIT 1000");
     40
     41my $update_query = $db->prepare_cached("UPDATE storage_object SET ext_id_basename = ?, dir_id = ? WHERE so_id = ?");
     42
     43# turn of fkeys, otherwise we can change storage_object.dir_id to a
     44# non-existant value
     45$db->do("SET FOREIGN_KEY_CHECKS=0");
     46#$db->do("UPDATE storage_object SET dir_id = 0");
     47
     48# completely reset the directory table
     49#$db->do("DELETE FROM directory");
     50#$db->do("ALTER TABLE directory AUTO_INCREMENT = 1");
     51# make sure these duplicates can't happen again
     52#$db->do("alter table directory add unique key(dirname,parent_id)");
     53# seed the root ('/') directory
     54#$db->do("INSERT INTO directory VALUES(1, '/', 1)");
    3355
    3456my $i = 0;
    35 while ($query->execute and $query->rows) {
    36     print "foo\n";
    37     while (my $row = $query->fetchrow_hashref) {
     57while ($work_query->execute and $work_query->rows) {
     58    while (my $row = $work_query->fetchrow_hashref) {
    3859        $i++;
    3960        my $key = parse_neb_key($row->{'ext_id'});
     
    4162
    4263#printf("dirizing %20s basename: %20s parent_id %10d\n", $key, basename($row->{'ext_id'}), $parent_id);
    43         printf("$i/$n dirizing %s\n", $key->path);
     64#        printf("$i dirizing %s\n", $key->path);
    4465
    45         my $q = $db->prepare_cached("UPDATE storage_object SET ext_id_basename = ?, dir_id = ? WHERE so_id = ?");
    46         $q->execute(basename($row->{'ext_id'}), $parent_id, $row->{'so_id'});
    47         $db->commit;
     66        $update_query->execute(basename($row->{'ext_id'}), $parent_id, $row->{'so_id'});
    4867    }
    49     $query->finish;
     68    $db->commit;
     69    printf("### COMMIT ###\n");
     70    $work_query->finish;
     71    printf("dirized $i\n");
    5072}
     73
     74$db->do("SET FOREIGN_KEY_CHECKS=1");
     75$db->commit;
  • branches/eam_branches/20090522/Nebulous-Server/t/02_config.t

    r23932 r24557  
    88use warnings;
    99
    10 use Test::More tests => 21;
     10use Test::More tests => 22;
    1111
    1212use lib qw( ./t ./lib );
     
    109109    is($config_db1->dbpasswd, "boo2", "dbpasswd");
    110110}
     111
     112# memcached_servers
     113{
     114    my $config = Nebulous::Server::Config->new(
     115            memcached_servers => ['127.0.0.1:11211'],
     116        );
     117
     118    is_deeply($config->memcached_servers, ['127.0.0.1:11211'], "memcached_servers");
     119}
  • branches/eam_branches/20090522/Nebulous-Server/t/75_parse_neb_key.t

    r23932 r24557  
    1010use Test::More;
    1111
    12 plan tests => 99;
     12plan tests => 106;
    1313
    1414use lib qw( ./t ./lib );
     
    2828    is($key->path, 'foo/bar/baz/quix', 'path');
    2929    is($key->volume, undef, 'volume name');
    30     is($key->soft_volume, undef, 'soft volume name');
     30    is($key->hard_volume, undef, 'soft volume name');
    3131}
    3232
     
    3636    is($key->path, 'foo/bar/baz/quix', 'path');
    3737    is($key->volume, undef, 'volume name');
    38     is($key->soft_volume, undef, 'soft volume name');
     38    is($key->hard_volume, undef, 'soft volume name');
    3939}
    4040
     
    4444    is($key->path, 'foo/bar/baz/quix', 'path');
    4545    is($key->volume, undef, 'volume name');
    46     is($key->soft_volume, undef, 'soft volume name');
     46    is($key->hard_volume, undef, 'soft volume name');
    4747}
    4848
     
    5252    is($key->path, 'foo/bar/baz/quix', 'path');
    5353    is($key->volume, undef, 'volume name');
    54     is($key->soft_volume, undef, 'soft volume name');
     54    is($key->hard_volume, undef, 'soft volume name');
    5555}
    5656
     
    6060    is($key->path, 'foo/bar/baz/quix', 'path');
    6161    is($key->volume, undef, 'volume name');
    62     is($key->soft_volume, undef, 'soft volume name');
     62    is($key->hard_volume, undef, 'soft volume name');
    6363}
    6464
     
    6868    is($key->path, 'foo/bar/baz/quix', 'path');
    6969    is($key->volume, undef, 'volume name');
    70     is($key->soft_volume, undef, 'soft volume name');
     70    is($key->hard_volume, undef, 'soft volume name');
    7171}
    7272
     
    7777    is($key->path, 'foo/bar/baz/quix', 'path');
    7878    is($key->volume, 'boing', 'volume name');
    79     is($key->soft_volume, 1, 'soft volume name');
     79    is($key->hard_volume, undef, 'soft volume name');
    8080}
    8181
     
    8585    is($key->path, 'foo/bar/baz/quix', 'path');
    8686    is($key->volume, 'boing', 'volume name');
    87     is($key->soft_volume, undef, 'soft volume name');
     87    is($key->hard_volume, 1, 'soft volume name');
    8888}
    8989
     
    9494    is($key->path, 'bar/baz/quix', 'path');
    9595    is($key->volume, 'foo', 'volume name');
    96     is($key->soft_volume, 1, 'soft volume name');
     96    is($key->hard_volume, undef, 'soft volume name');
    9797}
    9898
     
    102102    is($key->path, 'bar/baz/quix', 'path');
    103103    is($key->volume, 'foo', 'volume name');
    104     is($key->soft_volume, 1, 'soft volume name');
     104    is($key->hard_volume, undef, 'soft volume name');
    105105}
    106106
     
    110110    is($key->path, 'bar/baz/quix', 'path');
    111111    is($key->volume, 'foo', 'volume name');
    112     is($key->soft_volume, 1, 'soft volume name');
     112    is($key->hard_volume, undef, 'soft volume name');
    113113}
    114114
     
    118118    is($key->path, 'bar/baz/quix', 'path');
    119119    is($key->volume, 'foo', 'volume name');
    120     is($key->soft_volume, 1, 'soft volume name');
     120    is($key->hard_volume, undef, 'soft volume name');
    121121}
    122122
     
    126126    is($key->path, 'bar/baz/quix', 'path');
    127127    is($key->volume, 'foo', 'volume name');
    128     is($key->soft_volume, 1, 'soft volume name');
     128    is($key->hard_volume, undef, 'soft volume name');
    129129}
    130130
     
    135135    is($key->path, 'bar/baz/quix', 'path');
    136136    is($key->volume, 'foo', 'volume name');
    137     is($key->soft_volume, undef, 'soft volume name');
     137    is($key->hard_volume, 1, 'soft volume name');
    138138}
    139139
     
    144144    is($key->path, 'bar/baz/quix', 'path');
    145145    is($key->volume, 'boing', 'volume name');
    146     is($key->soft_volume, 1, 'soft volume name');
     146    is($key->hard_volume, undef, 'soft volume name');
    147147}
    148148
     
    152152    is($key->path, 'bar/baz/quix', 'path');
    153153    is($key->volume, 'boing', 'volume name');
    154     is($key->soft_volume, undef, 'soft volume name');
     154    is($key->hard_volume, 1, 'soft volume name');
    155155}
    156156
     
    160160    is($key->path, 'bar/baz/quix', 'path');
    161161    is($key->volume, 'foo', 'volume name');
    162     is($key->soft_volume, 1, 'soft volume name');
     162    is($key->hard_volume, undef, 'soft volume name');
    163163}
    164164
     
    169169    is($key->path, 'bar/baz/quix', 'path');
    170170    is($key->volume, undef, 'volume name');
    171     is($key->soft_volume, undef, 'soft volume name');
     171    is($key->hard_volume, undef, 'soft volume name');
    172172}
    173173
     
    178178    is($key->path, 'bar/baz/quix', 'path');
    179179    is($key->volume, undef, 'volume name');
    180     is($key->soft_volume, undef, 'soft volume name');
     180    is($key->hard_volume, undef, 'soft volume name');
    181181}
    182182
     
    186186    is($key->path, 'bar/baz/quix', 'path');
    187187    is($key->volume, undef, 'volume name');
    188     is($key->soft_volume, undef, 'soft volume name');
     188    is($key->hard_volume, undef, 'soft volume name');
    189189}
    190190
     
    195195    is($key->path, 'bar/baz/quix', 'path');
    196196    is($key->volume, 'foo', 'volume name');
    197     is($key->soft_volume, undef, 'soft volume name');
     197    is($key->hard_volume, 1, 'soft volume name');
    198198}
    199199
     
    205205    is($key->path, 'foo/bar/baz/quix', 'path');
    206206    is($key->volume, undef, 'volume name');
    207     is($key->soft_volume, undef, 'soft volume name');
     207    is($key->hard_volume, undef, 'soft volume name');
    208208}
    209209
     
    213213    is($key->volume, undef, 'volume name');
    214214    is($key->path, 'foo/bar/baz/quix', 'path');
    215     is($key->soft_volume, undef, 'soft volume name');
     215    is($key->hard_volume, undef, 'soft volume name');
    216216}
    217217
     
    221221    is($key->path, 'foo/bar/baz/quix', 'path');
    222222    is($key->volume, undef, 'volume name');
    223     is($key->soft_volume, undef, 'soft volume name');
     223    is($key->hard_volume, undef, 'soft volume name');
    224224}
    225225
     
    230230    is($key->path, '', 'path');
    231231    is($key->volume, undef, 'volume name');
    232     is($key->soft_volume, undef, 'soft volume name');
     232    is($key->hard_volume, undef, 'soft volume name');
    233233}
    234234
     
    238238    is($key->path, '', 'path');
    239239    is($key->volume, undef, 'volume name');
    240     is($key->soft_volume, undef, 'soft volume name');
     240    is($key->hard_volume, undef, 'soft volume name');
    241241}
    242242
     
    246246    is($key->path, '', 'path');
    247247    is($key->volume, undef, 'volume name');
    248     is($key->soft_volume, undef, 'soft volume name');
     248    is($key->hard_volume, undef, 'soft volume name');
    249249}
    250250
     
    254254    is($key->path, '', 'path');
    255255    is($key->volume, undef, 'volume name');
    256     is($key->soft_volume, undef, 'soft volume name');
     256    is($key->hard_volume, undef, 'soft volume name');
    257257}
    258258
     
    262262    is($key->path, '', 'path');
    263263    is($key->volume, undef, 'volume name');
    264     is($key->soft_volume, undef, 'soft volume name');
     264    is($key->hard_volume, undef, 'soft volume name');
    265265}
    266266
     
    270270    is($key->path, '', 'path');
    271271    is($key->volume, undef, 'volume name');
    272     is($key->soft_volume, undef, 'soft volume name');
     272    is($key->hard_volume, undef, 'soft volume name');
     273}
     274
     275# stringification
     276
     277{
     278    my $txt = 'neb:///bar/baz';
     279    my $key = parse_neb_key($txt);
     280
     281    is("$key", $txt, "stringified");
     282}
     283
     284{
     285    my $txt = 'neb://foo.0/bar/baz';
     286    my $key = parse_neb_key($txt);
     287
     288    is("$key", $txt, "stringified");
     289}
     290
     291{
     292    my $txt = 'neb://~foo.0/bar/baz';
     293    my $key = parse_neb_key($txt);
     294
     295    is("$key", $txt, "stringified");
    273296}
    274297
     
    322345};
    323346like( $@, qr/requires a path/, "no path" );
     347
     348# params
     349eval {
     350    my $key = parse_neb_key();
     351};
     352like( $@, qr/key param is not optional/, "no params" );
     353
     354eval {
     355    my $key = parse_neb_key(undef);
     356};
     357like( $@, qr/key param is not optional/, "key is undef" );
     358
     359eval {
     360    my $key = parse_neb_key(undef, 'bar');
     361};
     362like( $@, qr/key param is not optional/, "key is undef" );
     363
     364eval {
     365    my $key = parse_neb_key('foo', 'bar', 'foo');
     366};
     367like( $@, qr/too many params/, "too many params" );
Note: See TracChangeset for help on using the changeset viewer.