Index: trunk/Nebulous-Server/lib/Nebulous/Server.pm
===================================================================
--- trunk/Nebulous-Server/lib/Nebulous/Server.pm	(revision 20090)
+++ trunk/Nebulous-Server/lib/Nebulous/Server.pm	(revision 20091)
@@ -1,5 +1,5 @@
 # Copyright (c) 2004-2008  Joshua Hoblitt
 #
-# $Id: Server.pm,v 1.92 2008-10-13 20:09:38 jhoblitt Exp $
+# $Id: Server.pm,v 1.93 2008-10-13 20:41:17 jhoblitt Exp $
 
 package Nebulous::Server;
@@ -296,4 +296,93 @@
 
 
+sub swap_objects
+{
+    my $self = shift;
+
+    my ($key1, $key2) = validate_pos(@_,
+        {
+            type        => SCALAR,
+            callbacks   => {
+                'is valid object key' => sub { $self->_is_valid_object_key($_[0]) },
+            },
+        },
+        {
+            type        => SCALAR,
+            callbacks   => {
+                'is valid object key' => sub { $self->_is_valid_object_key($_[0]) },
+            },
+        },
+    );
+
+    my $log = $self->log;
+    my $sql = $self->sql;
+    my $db  =$self->db;
+
+    $log->debug("entered - @_");
+
+    # ignore volumes
+    $key1 = parse_neb_key($key1);
+    $key2 = parse_neb_key($key2);
+
+    # order of operations for the swap:
+    # key1 -> key1.swap
+    # key2 -> key1
+    # key1.swap -> key2
+
+    eval {
+        {
+            # key1 -> key1.swap
+            my $query = $db->prepare_cached($sql->rename_object); 
+            # this SQL statment takes the new key name as the first param
+            my $rows = $query->execute($key1->path . ".swap", $key1->path);
+
+            # if we affected more then one row something very bad has happened.
+            unless ($rows == 1) {
+                $query->finish;
+                $log->logdie("affected row count is $rows instead of 1");
+            }
+        }
+
+        {
+            # key2 -> key1
+            my $query = $db->prepare_cached($sql->rename_object); 
+            # this SQL statment takes the new key name as the first param
+            my $rows = $query->execute($key1->path, $key2->path);
+
+            # if we affected more then one row something very bad has happened.
+            unless ($rows == 1) {
+                $query->finish;
+                $log->logdie("affected row count is $rows instead of 1");
+            }
+        }
+
+        {
+            # key1.swap -> key2
+            my $query = $db->prepare_cached($sql->rename_object); 
+            # this SQL statment takes the new key name as the first param
+            my $rows = $query->execute($key2->path, $key1->path . ".swap");
+
+            # if we affected more then one row something very bad has happened.
+            unless ($rows == 1) {
+                $query->finish;
+                $log->logdie("affected row count is $rows instead of 1");
+            }
+        }
+
+        $db->commit;
+        $log->debug("commit");
+    };
+    if ($@) {
+        $db->rollback;
+        $log->debug("rollback");
+        $log->logdie("database error: $@");
+    }
+
+    $log->debug("leaving");
+
+    return 1;
+}
+
+
 sub replicate_object
 {
