2011-05-25

Hot deploy in Jetty a war file built by Jenkins

We use Jenkins to build our application as a war file and we wanted to deploy it in a Jetty server to provide a manual testing environment.
So, we installed Jetty on our Ubuntu machine using 'sudo apt-get jetty libjetty-extra'
By default, when you copy a war file to Jetty webapps directory, nothing happens because Jetty scans this directory only at startup. So, we could stop/start Jetty daemon but it requires granting some privileges to the user running Jenkins and also we may want to deploy more than one application without stoppîng the ones that are already running.

Another solution is to use Jetty's ContextDeployer hot deploy.

This means editing /etc/jetty/jetty.xml and setting the scanInterval of ContextDeployer to lowest possible value: 1 second and then restart Jetty.


<Call name="addLifeCycle">
<Arg>
<New class="org.mortbay.jetty.deployer.ContextDeployer">
<Set name="contexts"><Ref id="Contexts"/></Set>
<Set name="configurationDir"><SystemProperty name="jetty.home" default="."/>/contexts</Set>
<Set name="scanInterval">1</Set>
</New>
</Arg>
</Call>

Now we must create a context file for our war file in /etc/jetty/contexts directory. Let's call it myapp.xml and let's point it to the location of the war file from last successful build in Jenkins.

<?xml version="1.0"  encoding="ISO-8859-1"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<Configure class="org.mortbay.jetty.webapp.WebAppContext">
<Set name="contextPath">/myapp</Set>
<Set name="war">/var/lib/jenkins/jobs/MyProject/lastSuccessful/archive/trunk/myapp/target/myapp-0.0.1-SNAPSHOT.war</Set>
</Configure>

In order to deploy we just have to update our context file which can be easily done by executing 'touch /etc/jetty/contexts/myapp.xml'. We can then add it as a step in our main job in Jenkins if we want want continuous deployment or we can create a separate job if we want to control when we deploy a new version.

2011-04-27

GWT testing using Maven and Eclipse

When developing an application using Google Web Toolkit, it's a good practice to have both unit tests which do not require GWT and GWT tests for custom widgets or integration.
If you use Maven, you should apply the default naming convention of the Maven GWT plugin : *Test.java for standard unit tests and GwtTest*.java for GWT test cases. This way you have nothing to configure in your pom.xml.

Then you'll get errors from the GWT compiler because your unit tests are located in same java packages as your GWT application code but in a different source directory (e.g. src/test/java) and the compiler cannot find their source files. While these errors are not fatal and could be ignored, they are annoying. You can get rid of them by excluding your unit test classes by file pattern in your .gwt.xml file like below:


<source path='client' excludes="**/*Test.java,**/Mock*.java" />
<source path='shared' excludes="**/*Test.java" />

When you will run your GWT application, you may see error messages like:
[ERROR] [MyApp] - Line 13: No source code is available for type com.google.gwt.junit.client.GWTTestCase; did you forget to inherit a required module?

It does not prevent your application from running but they are annoying.
You can get rid of them by moving your GWT test cases to a dedicated source directory that you will exclude from the classpath of your Eclipse run configuration.
Finally, you'll put your standard unit tests under "src/test/java" and your GWT tests under "src/gwt-test/java". In your pom.xml, you have to use the build-helper-plugin to add this extra test directory.


<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>add-test-source</id>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>src/gwt-test/java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>


If you want to speed up your GWT tests, you can launch them from a GWT test suite but then you must configure the Maven plugin for running only your test suite otherwise you'd end up running same test twice. My naming convention is Gwt*Suite.java which works well with the two other conventions.



<plugin>
<groupid>org.codehaus.mojo</groupid>
<artifactid>gwt-maven-plugin</artifactid>
<version>2.2.0</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- Run only test suites not individual test cases. -->
<includes>**/Gwt*Suite.java</includes>
</configuration>
</plugin>

2010-04-29

Installer Hudson sur un serveur OVH

Pour installer le serveur d'intégration continue Hudson sur un serveur dédié OVH tournant Ubuntu, le plus pratique c'est de partir du package Debian et de suivre les instructions.
Le script va créer un utilisateur hudson, installer les binaires, les fichiers de configuration et le script de démarrage/arrêt.

Par défaut, l'espace disque est sous /home.
Si vous n'avez pas repartitionné votre serveur, vous pouvez déplacer la home et les logs de hudson.

# Stoppons Hudson
sudo /etc/init.d/hudson stop
# Passons sous /home/hudson
sudo mv /var/lib/hudson /home
sudo ln -s /home/hudson /var/lib/hudson
sudo mkdir /home/hudson/log
sudo mv /var/log/hudson/hudson.log /home/hudson/log/hudson.log
sudo ln -s /home/hudson/log/hudson.log /var/log/hudson/hudson.log
sudo chown -R hudson:nogroup /home/hudson
# Demarrons Hudson
sudo /etc/init.d/hudson start

La version Debian est un peu en retard sur la dernière version d'Hudson, voici comment la mettre à jour:

# Stoppons Hudson
sudo /etc/init.d/hudson stop
# Sauvegarde du war existant et download de la derniere version
cd /usr/share/hudson
sudo mv hudson.war hudson.war.old
sudo wget http://hudson-ci.org/latest/hudson.war
# Demarrons Hudson
sudo /etc/init.d/hudson start


2010-04-17

Mise en place d'un serveur de build

Nous avions besoin d'un serveur de projet (wiki, intégration continue, subversion, ...), j'ai retenu 2 possibilités:
  • Une solution "Software as a Service"
  • Un serveur dédié
Software as a Service

On trouve beaucoup d'offres très bon marché (moins de 10 euros par mois pour une petite équipe) incluant un dépôt Subversion et une gestion de projet basée sur Trac ou Redmine mais il manque l'intégration continue

Atlassian propose avec JIRA Studio une solution complète a un prix correct et c'est probablement la solution que nous aurions retenue si nous n'avions pas aussi eu à installer d'autres applications comme Nexus. Donc nous sommes partis sur l'option serveur dédié en tout cas pour quelques mois.

Serveur dédié

J'ai regardé 3 solutions françaises: Dédibox, Gandi et OVH.

Gandi est une offre cloud computing très souple basée sur Xen, on achète des parts de serveur 12 € HT/mois qui correspondent à du CPU, de la RAM et du disque.
On peut provisionner plus de parts à l'heure près.
Cette offre me semblait sous dimensionnée en terme de CPU, disque et bande passante et dès qu'on rajoute des parts, la facture monte vite.

J'ai ensuite comparé un Dedibox XL et un OVH Super plan mini qui sont assez proches à 49.99€ HT/mois.
Au final j'ai opté pour OVH principalement parce qu'ils incluaient 100 Go d'espace de sauvegarde contre 10 chez Dedibox. De manière générale, quand on a beaucoup de données à sauvegarder, les prix grimpent.

Mon serveur était disponible moins d'une heure plus tard.






2009-04-09

Créer des interfaces java est-il anti agile?

Créer des interfaces java facilite le découplage, permet d'utiliser des mocks pour les test unitaires, de changer d'implémentation, de créer des points d'interception mais peut-on considérer que c'est une pratique anti agile? Ma réponse est bien sur "Ça dépend" ;)

Oui si on considère que c'est du sur design (YAGNI) et qu'on attend d'avoir complètement défini les interfaces pour commencer a implémenter les classes concrètes.

Le Test Driven Design conduit à créer des classes concrètes, introduire des interfaces dans ce processus itératif le ralentit.

Par contre, on peut au cours d'une session TDD avoir besoin de créer une implémentation mock d'un DAO par exemple et au final en extraire une interface par refactoring quand le design s'est stabilise. On obtient ainsi une interface dont la conception a émergé du TDD et un mock utile pour les test unitaires des classes consommant cette interface.

Il ne s'agit pas non plus de créer des interfaces a tout bout de champ mais la où ça fait sens comme la couche d'accès aux données (d'où mon exemple sur un DAO) ou tout point d'intégration avec un module ou un composant de l'infrastructure.

Donc c'est plutôt le moment ou l'on crée une interface et la façon dont on la crée qui peut être non agile.

2008-08-10

FindBugs on a Wicket + Spring application

FindBugs is a great static analysis tool and it helped me to find several bugs but recently we switched to Wicket 1.3 framework for web development and we got few false positives which were related to using Spring with Wicket.

Serialization

We had Wicket page classes with fields being injected by Spring using the @SpringBean annotation.
FindBugs complained that these fields should have been serializable or transient (SE_BAD_FIELD error) and this seemed an issue as Wicket does use serialization a lot to save pages into its session.
In fact, it turned out to be a false postive because Wicket manages this by using Spring dynamic proxies.


Unitialized fields in constructor

Another FindBugs complaint in Wicket page classes was about de-referencing fields in constructor before having initialize them (UR_UNINIT_READ error).
Again, this turned out to be a false positive because our pages did extend WebPage class that takes care of injecting all SpringBean annotated fields using a PropertyResolver.
Something to remember: the default PropertyResolver is able to initialize private fields and ignores setters.

Conclusion

Using Spring beans in Wicket pages introduces a lot of dynamicity that defeats static analysis when dealing with object initialization and serialization.
FindBugs is so valuable that it is worth excluding these rules on Pages and having a naming convention for these classes makes it easier to do. Our page classes are now named with the "Page" suffix.

2008-04-19

My first (useful) script in Groovy

We had a large number of XML files to modify and found that Groovy with its GPath syntax was the right tool. Here is an example that takes a (simplified) XML file and changes the value of one attribute for a subset of nodes.

<?xml version="1.0"?>
<design>
<process>
<variable id="V1" visible="true" />
<variable id="V2" visible="false" />
<variable id="V3" visible="false" />
</process>
</design>


And the script to change all XML files in the current directory.
I found it easier to write and debug it than using a mix of java and XSL.


def basedir = new File( ".")

// Create a directory for patched files
new File("patched").mkdir()

// Get files with ".xml" extension
files = basedir.listFiles().grep(~/.*\.xml$/)

// Iterate on the files
files.each {
patchXML(it)
}

def patchXML(file) {
println "-------------------"
println "Patching $file.name"

def design = new XmlParser().parse(file)
def modified = false

for (variable in design.process.variable) {
switch (variable.@id) {
case "V1":
case "V2":
if (variable.@visible == "false") {
variable.@visible = "true"
modified = true
}
}
}
if (modified) {
new File("patched/$file.name").withPrintWriter() {
new XmlNodePrinter(it).print(design)
}
println "Patched $file.name is in \"patched\" directory"
} else {
println "$file.name was not modified"
}
println "-------------------"
}

2008-04-10

Hibernate without a DBA: a sure path to failure!

Recently, my team had to deploy a Java web application that we bought from a small company. They used Hibernate as their Object Relational Mapping and were using it to generate their database schema.

In order to make their installation process easier, the application was creating or updating the database schema at startup time. This may sound like a nice idea but in most companies, you don't want to grant your application DROP, CREATE or ALTER privileges as it could be a security vulnerability if your web application gets hacked. Fortunately, Hibernate provides you with ant tasks to generate your schema creation script and if your customer runs on a different database server, you will generate a script for it.

That's great but as soon as we started to run our load tests, we got tons of deadlock errors on SQL Server 2005:

Transaction (Process ID 54) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
A typical developer reaction is to accuse Hibernate, the driver or the database engine. After a quick search on Google I was under the impression that it should be a bug in the application.

Application bugs


The show_sql flag in Hibernate configuration is a useful tool, it helped the developers to find that under some circumstances the application would save the same data twice. They fixed the code,we ran the load test again and observed a great performance improvement but still deadlock errors.

Another search on Google leaved me with more questions than answers with few exceptions like this excellent article from Bart Duncan. After reading it, you should be convinced that you need some help from a good DBA. We were fortunate to have a good DBA team even though I found it difficult to explain them what statements or queries we were using because they were generated by Hibernate and not written by ourselves.
The most difficult part was to obtain a trace on the database server when reproducing a deadlock. Many trace flags can be too invasive and change your timing preventing you to reproduce the deadlock. We found that the trace flag 1222 was the most helpful to get data without modifying the execution timing.

Unicode encoding

Our DBA analyzed the data and found a deadlock cause: inserting unicode strings into a varchar column that was indexed, this caused a conversion and index scan resulting in a concurrency between 2 threads executing same statement updating different rows but using same index. Solution: convert column types to nvarchar or change your JDBC driver settings to avoid encoding string parameters in Unicode, both will also bring you an additional gain in performance.

Missing index on a foreign key

We changed the JDBC driver setting and ran again the load test: deadlocks again but new ones.
Our DBA did analyze the new trace and quickly found a foreign key in a one-to-many relationship which was not indexed, this resulted in an index scan and deadlock on concurrent updates. This is something that you can and should specify in your Hibernate mappings.

Other issues

You can get deadlocks also when using clustered indexes. It turns out that by default primary keys in SQL Server are clustered indexes. So by using Hibernate schema, you will get clustered indexes for all your primary keys, it's usually not a problem especially for naturally growing keys like identity columns but if you are using randomly generated strings for your ids it can be a problem.

Conclusion

Hibernate like other ORMs is a useful tool but you should use its schema generation feature for what it is: a help to speed up your initial development but you will not avoid fine tuning of your table definitions, indexes and only an experimented DBA can help you there.

Do not believe that by using Hibernate you will be able to migrate easily from one database engine to another one, you will almost always end up tuning your schema to solve deadlocks or performance issues in a specific way.

2008-02-27

Public Maven repositories and wrong POMs

I experienced an issue with log4j 1.2.15: it comes with a POM that wrongly forces you to include extra dependencies that should be optional (e.g. Java mail if you don't plan to use the SMTPAppender feature). This issue has been reported as bug #43304 to log4j team.

My first reaction was to exclude these dependencies in my project pom.xml but this did not work (I did not take time to investigate why). Anyway, it was faster for me to patch the log4j POM in our intranet repository.

Lesson learned: managing dependencies can be hard and you should not depend on public repositories as they can be wrong sometimes. Make sure your team has an Intranet repository and make it simple to update with a good repository manager like Artifactory.

2007-10-26

Not fully convinced by Maven 2

After several weeks of trying to migrate our build process to Maven 2, we decided to stop due to:

  • Incompatibility with WebLogic: we use BEA Weblogic ant tasks that are not compatible with Maven build lifecycle phases. For instance, appc mixes generate-sources, compile and package; for this reason the maven-weblogic-plugin that uses these tasks has same flaw. So if you need to use other Maven plugins you must implement workarounds and attach them to unnatural phases to ensure they get executed before or after appc. See my previous post.
  • Lack of flexibility: by nature, Maven is not flexible, the only ways to get more flexibility is to use profiles, maven-antrun-plugin or to write your own plugin in java: not really simple nor very productive especially if you need to write simple workarounds. It's strange because there seems to be a growing tendency in open source build tools to enable more flexibility: ant 1.8 feature list includes logic/control flow features from ant-contrib (for, if, while, etc…), gant uses groovy as build scripting language on top of ant, buildr uses Ruby.
  • Lack of auditability: with Maven's convenient way to download missing parts and self update, it's difficult to know exactly what was used to build one version of your product. The fact that Maven mixes tool's dependencies of the tool (maven+plugins) and dependencies of the projects being built into one single local repository surely does not help here. it would be better if separation of concerns was implemented in local repository to ensure that the dependencies managed by the developers do not get polluted by dependencies that are out of its control scope.
  • Issues are difficult to diagnose: I've got examples about classpath, system properties where it's difficult to find the culprit between Maven, plugins or dependencies.
  • Plugins quality ranks from excellent to terrible: this is not a Maven issue by itself but combined with above mentioned difficulty to diagnose it can lead to painful situations.

So, our next approach will be to use ant for building and restrict Maven to managing dependencies and generating project site and quality reports.

2007-09-15

How to connect to an MS Access database using Ruby and ODBC

If you search for an answer to this question in Google, you will get mostly sarcastic answers and if you're lucky maybe some help.

You must first download Ruby ODBC from Christian Werner's site and copy odbc.so and odbc_utf8.so into the ...\ruby\1.8\i386-msvcrt directory where you installed Ruby. Uf you have installed InstantRails in default location, it should be under C:\InstantRails\ruby\lib\ruby\1.8\i386-mswin32

In the example below I connect to an Access file (c:\ruby.mdb) and print the contents of a table (Table1)

require 'DBI'

access_dsn_base = 'DBI:ODBC:Driver=Microsoft Access Driver (*.mdb);DBQ='
access_file = 'C:\ruby.mdb'

DBI.connect(access_dsn_base+access_file) do |dbh|
dbh.select_all('Select * From Table1') {|row| p row}
end


Similarly, you can use DBI:ODBC to read MS Excel files.
In the example below I connect to an Excel file (c:\my_file.xls) and print the contents of a spreadsheet (Sheet1)

require 'DBI'

excel_dsn_base = 'DBI:ODBC:Driver={Microsoft Excel Driver (*.xls)};DBQ='
excel_file = 'C:\my_file.xls'

DBI.connect(excel_dsn_base+excel_file) do |dbh|
dbh.select_all('Select * From [Sheet1$]') {|row| p row}
end


My configuration is Windows XP + MS Access 2000 + MS Excel 2002 + Ruby 1.8.6 + Ruby ODBC 0.9995

2007-09-12

WebLogic 9.2 is not Maven 2 friendly

Using Maven 2 is more difficult when you use a platform like BEA WebLogic 9.2 because of their "split directory" convention which creates a gap with Maven's own conventions.

A first approach could be to avoid using the split directory structure, however it's not that easy because it comes with a set of specific ant tasks to pre-compile your JSPs, generate a web service from an EJB, package an ear file, ...
These tasks are not open sourced and are too high level to be easily integrated into Maven: for instance, if you want to pre-compile your JSPs, you cannot use anymore jspc because it has been deprecated in favor of appc which depends on the split directory structure.
This makes almost impossible to write an equivalent Maven plugin for a 3rd party, only BEA could do it.

Another issue with these tasks is that they are defined in weblogic.jar: a 50 MB jar which contains a lot of stuff that may collides with dependencies in your classpath, especially because BEA chose to specify a relative classpath in its jar manifest.

An alternative is to use the WebLogic ant tasks from Maven using the antrun plugin, unfortunately this plugin is poorly documented and does not offer easy options to configure a classpath to integrate weblogic.jar. Also, antrun retrieves its own version of ant from Maven's repository that may collide with the one required by WebLogic's tasks; you can find workarounds for this but then you will have to trick Maven to make it think that it has generated the artifact generated by appc.

So, unless BEA endorses Maven and provides its own plugins, it will be difficult to use Maven for a non trivial WebLogic application. My next step will be to try to use ant and Maven's antlib in order to be able to use Maven's dependency management.

P.S.: I just found Hussein Badakhchani's excellent post about maven and appc, I may try his approach as well.

2007-08-21

Windows Environment Variables Trap

In Windows, you can easily define environment variables from the "My Computer" icon on your desktop. It's convenient but you can't define the evaluation order, so Windows does it for you but it does it wrongly (at least on Windows XP).

Define these variables:

V1=1
V2=%V1%-2
V3=%V2%-3
V4=4-%V5%
V5=5-%V6%
V6=6

Here is what you get:

V1=1
V2=1-2
V3=1-2-3
V4=4-%V5%
V5=5-6
V6=6


So, V4 was not correctly expanded.
We can also see that the evaluation is partly based on alphabetical order (V1, V2, V3) but that there were 2 passes as V5 is correct.

So, if you want to get safe set an evaluation order on your variables by setting them in your autoexec.bat file.

2007-08-15

My First Ruby on Rails project

It's been a while since I wanted to refactor my PHP+Smarty web site and also to implement additional database driven features. The main purpose of this application is to manage table tennis tournament results.

CakePHP

Being hosted on a PHP box, my first idea was to look for Ruby on Rails clone in PHP.
I found CakePHP to be the only serious one able to run on PHP4 so the choice was easy.
I spent few hours during 3 weeks to learn the framework and start my project, there was no book to help so I relied mostly on simple tutorials and users forums.
CakePHP is a good framework with may useful features (some of them are even more advanced than Ruby on Rails equivalent ones) and a great community but documentation is sparse and worse: it suffers from PHP's poor syntax (at least from a Java developer's standpoint).
After 3 weeks, I decided to stop and switched to Ruby on Rails even if it meant switching to a new web hosting company.

Switching to Ruby on Rails

I bought the "Agile Web Development with Rails" book and read several tutorials.

Using existing database

First, I created my application using rails ipttc then I created a migration from my existing database.


ruby script/generate migration Initial
rake db:schema:dump


Then I copy/pasted from schema.rb into the up method of db/migrate/001_initial.rb

rake db:migrate

I found that my legacy schema was not following some of Rails conventions like having a numerical id for tables, I decided to keep it simple and adapt the rails conventions, maybe I'll dig further if needed.

Being a lazy typist, I looked at ways to generate my models from existing database and I found Dr Nic's Magic Model Generator which created 7 models with validation rules in a snap, Thanks Doc! By reviewing the generated models, I was able to learn quickly about validations and relations and I really discovered something unexpected: it did create some kind of indirect relations: "has many through".

Tournament has many Medals.
Player has many Medals.
Tournament has many Players through Medals.

And it does make a lot of sense, it's like saying:

Tournament has many Medalists.

After that, I started to play with scaffolding and I was a bit disappointed because it did not take into account relations between models. I searched for better scaffolding and found ActiveScaffold and Hobo. ActiveScaffold provides dynamic scaffolding using Ajax and nice presentation. Hobo is more a framework on top of Rails and provide additional nice features like a security model with users, roles and permissions. Both of them are very promising but they provide only dynamic scaffolding while I am more looking for a code generator to be able to learn and modify things for my needs. Also, I'm still too new in Rails to be able to select an additional framework, I must try to understand the standard Rails features first.

Fortunately, I was also looking at RESTful implementation in Rails and found that there was a new scaffold code generator that was deprecating the original one.
The good thing about scaffold_resource is that it lets you to generate the model, the views, the controller and the database table in migration at once.
You just have to list the name of your fields and types, for instance for Player and Country:


ruby script/generate scaffold_resource Player full_name:string first_name:string last_name:string birth_date:date country_id:integer gender:string class:integer dead:boolean eligible:boolean

ruby script/generate scaffold_resource Country code:string name:string

rake db:migrate


Conclusion

My application will be RESTful and I will create a new database schema.

2007-08-12

Code Red Alert

A little story that happened to me as a hobbyist webmaster of www.ipttc.org

In previous months, I have seen our network bandwidth consumption increasing, 2 months ago I found that there was a lot of traffic coming from servers in Vietnam where our sport is not very developed but at this was at the end of the month I did not pay too much attention.

On June, 13th, I noted a major traffic increase, I looked at the most downloaded pages and was surprised to find audio files (.wma) while we don't distribute music of course.

Then, I found that there were about 1500 such files in one directory which was the upload directory of forum for attachments. So, everything indicated that a hacker did exploit a vulnerability in the file upload module of the forum.
I decided to remove the files but it was not possible, so I renamed the directory and I logged a support ticket to get administrators to do the job.
I un-installed the file upload module and updated the forum software to most recent version.

I sent a mail to my committee qnnouncing that our web site would probably get unavailable because our network bandwidth for the month could be exceeded within next hours or days and that the downtime could last until end of the month.

Next morning, I got a mail from support saying that they deleted the files.

Unfortunately, our bandwidth got exceeded during the night and so our site was down.

I decided to look carefully at the web server log files and I found that all requests for music files came from one site www.muzic9.com. In fact, this site proposes "free" music, you choose an album and then click on a song, it then redirects transparently to an external site. So it means that when clicking on some songs you actually downloaded them from www.ipttc.org! I sent an email to the webmaster asking him to delete all links pointing to our site get and that he no longer accepts such links.

I did a "whois" query to find the site owner:


TUAN
TUAN TUAN (tuan.maxviet@gmail.com)
1.8633630
Fax: 1.8633630
Some where in VN
address
HCM, HCM 70000
VN


So the owner was from Vietnam, same country that consumed our bandwidth last month.
I did send same email to this address. No need to say, I never got any reply.

I put some additional protections in place and now monitor more seriously my bandwidth consumption report and web log files.

2007-08-10

Subversion quick protocol benchmark

Subversion lets you choose the protocol used to connect from client to server, it has an impact on the authentication scheme but also on data transfer rate.

I ran a checkout on 2500 files and 50 MB with client running locally on server. As expected, "svn" was the fastest: "http" was 66% slower and "https" was 135% slower.

Also an export of same source tree is much faster than a checkout (up to 3 times faster in my tests depending on the number of files) because svn client does not need to create a local copy of each file nor metadata files (checksums, logs, ...) in .svn directories. So, it could be a little optimization for a build that does not need to commit any change.

Of course, when the client is remote, the impact of a slow network connection tends to lower these differences.