Command Server
Michal Gornisiewicz
michal-bzr at mxg.id.au
Mon Nov 27 08:39:20 GMT 2006
Hi all,
I created a quick hack of a "command server" plugin which speeds up bzr
for really basic operations - making things /feel/ more responsive. The
idea is similar to the shell plugin, but without having to use a
different shell.
Instead you start a server process which listens on a UNIX socket and
instead of bzr, run a script ("fbzr") which connects to the server and
just passes the command line arguments.
This should work with most commands, but I've only tested with a few
simple ones (diff, log, status).
I thought I'd post it here in case someone finds this useful.
Some example timings:
bzr rocks 0.88s user 0.09s system 100% cpu 0.970 total
fbzr.py rocks 0.04s user 0.02s system 100% cpu 0.060 total
bzr status 1.24s user 0.17s system 100% cpu 1.408 total
fbzr.py status 0.05s user 0.01s system 15% cpu 0.386 total
Caveats:
1. You need to use bzr (not fbzr) to control the command server.
2. Only stdout (not stderr) is passed from the server.
eg. --version won't show anything
3. The environment used is that of the server, not client (except for
the working dir).
4. No bells or whistles whatsoever.
Attached:
__init__.py - the plugin
fbzr.py - run instead of bzr
Michal
PS - I'm NOT subscribed to the list.
-------------- next part --------------
# Copyright (C) 2006 Michal Gornisiewicz <michal-bzr at mxg.id.au>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License ONLY.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
A command server, for speeding up bzr operations.
"""
import os
import cPickle as pickle
import socket
import sys
import bzrlib.commands
from bzrlib.commands import Command, register_command, display_command, Option
SOCKET_FN = "%s/.bazaar/cmdsrv" %os.getenv("HOME")
class cmd_command_server(Command):
"""Controls the command server.
"""
aliases = ["cmdsrv"]
takes_args = ['subcommand']
def __init__(self):
self._sc_funs = {
"start": self.start_server,
"stop": self.stop_server,
"status": self.status_server,
}
def help(self):
text = ["%s\nSubcommands:" %self.__doc__]
subcoms = [
("start", "Start the command server."),
("stop", "Stop the command server."),
("status", "Check if the command server is running.")
]
indent = 2*" "
for n, d in subcoms:
text.append("%s%s" %(indent, n))
text.append("%s%s" %(2*indent, d))
text.append("")
return "\n".join(text)
def run(self, subcommand):
fun = self._sc_funs.get(subcommand)
if not fun:
raise CommandError("Unknown command-server command"\
" '%s'." %subcommand)
fun()
def start_server(self):
# TODO: check if socket already exists
pid = os.fork()
if 0 < pid:
return
os.chdir("/")
os.setsid()
os.umask(0)
pid = os.fork()
if 0 < pid:
return
s = socket.socket(socket.AF_UNIX)
try:
s.bind(SOCKET_FN)
s.listen(1)
while self._process_command(s):
pass
finally:
s.close()
os.unlink(SOCKET_FN)
def _process_command(self, s):
result = True
conn = None
try:
real_stdout = sys.stdout
conn, addr = s.accept()
client = conn.makefile()
dir = pickle.load(client)
if dir == "STOP":
result = False
elif dir == "STATUS":
client.write("Running.")
client.flush()
else:
argv = pickle.load(client)
os.chdir(dir)
sys.stdout = client
bzrlib.commands.main(argv)
finally:
sys.stdout = real_stdout
os.chdir("/")
if conn:
conn.shutdown(2)
return result
def stop_server(self):
try:
s = socket.socket(socket.AF_UNIX)
s.connect(SOCKET_FN)
s.send(pickle.dumps("STOP"))
except socket.error:
print "Can't connect to command server. Is it running?"
def status_server(self):
try:
s = socket.socket(socket.AF_UNIX)
s.connect(SOCKET_FN)
s.send(pickle.dumps("STATUS"))
data = s.recv(4096)
while data:
sys.stdout.write("%s\n" %data)
data = s.recv(4096)
except socket.error:
print "Not running."
register_command(cmd_command_server)
if __name__ == '__main__':
print "This is a Bazaar plugin. Copy this directory to"\
" ~/.bazaar/plugins to use it.\n"
else:
sys.path.append(os.path.dirname(__file__))
-------------- next part --------------
#!/usr/bin/python
# Copyright (C) 2006 Michal Gornisiewicz <michal-bzr at mxg.id.au>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License ONLY.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import os
import cPickle as pickle
import socket
import sys
def main(argv):
s = socket.socket(socket.AF_UNIX)
fn = "%s/.bazaar/cmdsrv" %os.getenv("HOME")
s.connect(fn)
server = s.makefile()
dir = os.getcwd()
s.send(pickle.dumps(dir))
s.send(pickle.dumps(sys.argv))
data = s.recv(4096)
while data:
sys.stdout.write(data)
data = s.recv(4096)
if "__main__" == __name__:
main(sys.argv)
More information about the bazaar
mailing list