2011-07-20 4 views
8

psycopg2を使用して同じネットワーク上の2台のマシン間でデータのコピーを作成するスクリプトを作成しています。私はpiping postgres psycopg2を使用したPythonでのコピー

psql -c -h remote.host "COPY table TO STDOUT" | psql -c "COPY table FROM STDIN" 

でコピーをして、いくつかの古い、醜いのbashを交換していますこれは、コピーを行うための最も簡単かつmost efficient方法の両方のように思えます。

buf = StringIO() 

from_curs = from_conn.cursor() 
to_curs  = to_conn.cursor() 

from_curs.copy_expert("COPY table TO STDOUT", buf) 
buf.seek(0, os.SEEK_SET) 
to_curs.copy_expert("COPY table FROM STDIN", buf) 

を...しかし、それはメモリに/ディスクにすべてのデータを保存含まれます。それはそうと同じように、StringIOをまたは一時ファイルをpythonで複製することは簡単です。

誰かがこのようなコピーでUnixパイプの動作を模倣する方法を考え出しましたか?私はPOpenに関係しないUnix-pipeオブジェクトを見つけることができないようです - おそらく最良の解決策はPOpenとサブプロセスを使用することです。読者はライターよりもはるかに高速で、かつテーブルが大きい場合、dequeはまだ、大きな取得します

from collections import deque 
from Exceptions import IndexError 

class DequeBuffer(deque): 
    def write(self, data): 
     self.append(data) 
    def read(self): 
     try: 
      return self.popleft() 
     except IndexError: 
      return '' 

buf = DequeBuffer() 

+0

好奇心は以下の解決策ですか? – agf

答えて

0

あなたが読み書きをサポートするために、サブクラス化しました両端キューを使用することができます全体を格納するよりも小さくなります。

さらに、dequeが空の場合はreturn ''がわかりませんが、空でない限り再試行するのではなく安全ですが、私はそれが推測できます。それが動作するかどうか私に教えてください。

コピーが完了したら、特にスクリプトがその時点で終了していない場合は、del bufを覚えておいてください。

12

あなたの呼び出しの1つを別のスレッドに入れる必要があります。私はちょうどあなたが残りを非常に簡単にするos.pipe()を使用できることに気付きました:

#!/usr/bin/python 
import psycopg2 
import os 
import threading 

fromdb = psycopg2.connect("dbname=from_db") 
todb = psycopg2.connect("dbname=to_db") 

r_fd, w_fd = os.pipe() 

def copy_from(): 
    cur = todb.cursor() 
    cur.copy_from(os.fdopen(r_fd), 'table') 
    cur.close() 
    todb.commit() 

to_thread = threading.Thread(target=copy_from) 
to_thread.start() 

cur = fromdb.cursor() 
write_f = os.fdopen(w_fd, 'w') 
cur.copy_to(write_f, 'table') 
write_f.close() # or deadlock... 

to_thread.join() 
+0

これは素晴らしい解決策です!なぜ私はスレッドオブジェクトを導入する必要があったのですか? – Demitri

+3

@Demitri、 'copy_from()'、 'copy_to()'はブロックコマンドです。操作が終了するまで戻りません。メインスレッドで最初の呼び出しを行った場合、パイプ上のデータを待つだけで、もう一方の呼び出しを行うことはできません。 –

+0

ああ、そうです。それはまだ新しいスレッドではブロックされますが、メインスレッドはパイプを余裕でフィードすることができます。ありがとう。 – Demitri

関連する問題