Thursday, February 11, 2010

Make Ubuntu faster

There are few very simple methods to make Ubuntu faster. Some of them work not only on Ubuntu, but on other linux systems as well.

Change dynamic linking to static one

When compiler generates binary file, elements which should connect with external libraries are only stubs. When running application for the first time (in a session), it is dynamically linked, which means stubs are replaced with real calls to libraries. This process takes some time. Open Office on my machine runs about 5 seconds for the first time, and 1-2 seconds every next time.

Fortunately there is a program called prelink, accessible from Ubuntu repositories.

sudo apt-get install prelink
sudo prelink -amR

After the second command prelink scans binaries specified in /etc/prelink.conf and modifies them replacing dynamic calls with static ones, but in binary files, so this change is permanent. Disadvantage of this solution is that after every update of processed program we need to run prelink again.

We can always go back to dynamic linking (undo prelink):

sudo prelink -au

You HAVE TO go back to dynamic linking if you want to remove prelink.

Get now what I'll need in a few miliseconds

Next useful program fastening Ubuntu is preloader. It uses magic (complicated algorithms) to predict what data is going to be necessary next and loads it before application asks.

You only need to install it:

sudo apt-get install preload

It should run automatically, but if for some reason it is not running:

sudo /etc/init.d/preload start

Koziołek says it consumes a lot of RAM, but I didn't notice :)

Run services in paralell

If you have more than one core, you can set your system to start services in paralell during startup. This is potentially dangerous, as there might be services which depend on each other.

Edit /etc/init.d/rc and find line CONCURRENCY=none. Change it to CONCURRENCY=startpar.

This post is here courtesy of Bartłomiej "Koziołek" Kuczyński, and is translation of his post in Polish.

Tuesday, January 12, 2010

Partial mocks in Mockito - Mock only what you need, left the rest to the original class

In Mockito you can not only create "regular" mocks, but also partial mocks. Let's assume we need to use instance of class A, and we want to mock it. We can do mock:
A aMock = Mockito.mock(A.class);
Sometimes, we want to use instance of real class A, but mock only part of it. Only one or few methods. With Mockito it is possible:
A a = Mockito.spy(new A());
So we spy real object, we can verify it's method calls, but we can also do that:
Mockito.when(a.methodCall()).thenReturn(1);
We can mock some of A's methods, leaving the rest to the real A instance.
For me it was useful while I was creating test involving user. User object's have ID, but there is only getter for it. ID is always set by database, and should never been changed by programmers, so there is only getter. Thanks to partial mocks, I mocked only getId() method, without need to add setId() just for testing purposes.

Monday, December 14, 2009

CouchDB

CouchDB is a new kind of database. It's not a relational database, it's not objective database. CouchDB just stores documents. A document is something like java map, it has keys and values. Values can be strings, numbers, dates, lists, maps, also binary attachments. Documents are accessible by pure http, REST service, in JSON format. CouchDB is written in Erlang, so it is well scalable for many processors/cores. (At least this is what it's authors claim ;)) Let's give it a try.

Installation

On ubuntu issue:

apt-get install couchdb

During installation, couchdb user was created. Now you can run database as a background process:

sudo -i -u couchdb couchdb -b

Ok, fire up your favorite browser and open page http://localhost:5984/ You should see something like: {"couchdb":"Welcome","version":"0.10.0"}

Not very useful, is it? Try going to http://localhost:5984/_utils/ This is Futon, CouchDB admin tool. From here you can create new databases and documents and manage them.

Simple operations by Futon

Create database tryme and some document. Field _id is generated automatically, add two more fields:

firstname: "Pawel"
surname: "Stawicki"

Click "Save document". You can see that field _rev was added automatically. Every change of every document is remembered, and you can always get the old version.

Protection

So there is one document in the database, let's protect it. Go to /etc/couchdb/local.ini and edit [admins] section. Add:

admin = <admin_password>

Password will be automatically hashed after run.

If you want to enable access from any machine, change bind_address from 127.0.0.1 to 0.0.0.0

Operations by RESTful HTTP interface

CouchDB can be accessed by RESTful http interface. Curl is one nice tool for it, so install it if you don't have it already on your system:

sudo apt-get curl

Now issue:

curl http://localhost:5984

You should see known welcome message. Try

curl http://localhost:5984/tryme

and some data about tryme database should appear. We can also list all existing databases:

curl http://localhost:5984/_all_dbs

Ok, all this stuff above you can do by the browser. But you can also create documents and databases in CouchDB by REST interface. Try this:

curl -X PUT http://localhost:5984/tryme/1 -d '{ "firstname": "Leszek", "surname": "Gruchała" }'

You just created a new document. In curly braces is document in JSON format. It's id however is not long stream of characters, but just "1". Much more predictable and repeatable. UUIDs are generally better. CouchDB can generate one for you:

curl http://leonidas:5984/_uuids
It generates one id. If you need more, you can pass "count" parameter:
curl http://leonidas:5984/_uuids?count=3

So we've seen that CouchDB uses JSON as documents format, and we can do operations by HTTP. However, from now on, I'll be using Futon because it is just easier. Futon is CouchDB administration tool (http://localhost:5984/_utils).

Creating view by map/reduce

JSON is JavaScript format, and it allows to put also functions into the document. Map functions (from map/reduce) are useful to create something similar to SQL view.

Let's add another document to our database, with following fields:

firstname: "Leszek"
surname: "Kowalski"

Now choose "Temporary view" from selection box on the right. Here you can write map and reduce functions. For view, map is enough, let's leave reduce empty for now. Create function:

function(doc) {
  if (doc.firstname == 'Leszek') {
    emit(doc.firstname, doc.surname);
  }
}

It filters documents to those with firstname "Leszek" only.

So we can filter documents to only those which interest us. What about joins? Can we get some document, and relevant documents data in one query? It's also possible. Let's add addresses to those guys in database. First, we need to distinguish documents related to persons from the ones related to addresses. For that, add type field to each person, and as value enter "person". Now, we'll need their id's, so copy/paste it somewhere.

Create address as a new document, and add those fields:

type: "address"
person_id: <id_of_person>
city: "New York"

The same for two remaining persons. Put some another city there. Ok, now our map function is a little more complicated:

function(doc) {
  if (doc.type == "person") {
    emit([doc._id, 0], doc);
  } else if (doc.type == "address") {
    emit([doc.person_id, 1], doc);
  }
}

This way we have person always next to her address.

We learn another CouchDB feature here - result of map is always sorted by key. In this case key is 2-element array, in which first element is the person id, and second one is 0 in case of person, 1 in case of her address. It's not like SQL join, we don't get all the data in one document, but still it answers our needs - we have person and it's address.

If we are interested in specific person, we can add parameter to GET request. But first we need to save our view in "desing document". Click "Save As..." button, fill in design document name (e.g. "reader") and view name (e.g. "person-address") and voila.

Design documents are special documents in database for storing views. You can have different design documents e.g. for readers and for writers or administrators. In desing document you can set a lot of stuff telling CouchDB how to render it's content (means how to change it into nice html). If you want to learn more about design documents, look into CouchDB book.

GET parameters for narrowing search

Now when our view is saved, we can use GET request to get it's content, and set parameters to limit what we get to person which we are interested in. Such URL: http://localhost:5984/tryme/_design/reader/_view/person-address?startkey=["1",0]&endkey=["1",1] will return person with _id=1 and it's address documents.

Another useful parameters are:

  • key - for specific key (not range, like in case of startkey, endkey)
  • descending=true - by default view is ordered by ascending key, set this parameter to order it descending
  • group_level - sets reduce level. Default is 0.
  • group=true - behaves like group_level set to maximum
  • revs_info=true - lists revisions of specified document. Applicable only to document selected by id, not to view

To understand group_level, we'll need reduce function. First, let's add some more parameters to our persons. Let's add "position" and "salary":

To one person add:

position: "manager"
salary: 5000
To second one:
position: "developer"
salary: 3000
and to third one:
position: "developer"
salary: 3500
Now create new view, with map and reduce functions:
//map:
function(doc) {
  emit([doc.position, doc._id], doc);
}

//reduce:
function(keys, values, rereduce) {
  var salaries = 0;
  for(i = 0; i < values.length; i++) {
    salaries += values[i].salary;
  }
  return salaries;
}

Save this view as "salaries". Now open URL http://leonidas:5984/tryme/_design/bla/_view/salaries and output is:

    {"key":null,"value":11500}

All values are grouped, and key is ignored.

Add parameter: http://leonidas:5984/tryme/_design/bla/_view/salaries?group_level=1 and it returns

{"key":["developer"],"value":6500},
{"key":["manager"],"value":5000}

Values are grouped for first level of key (first element of key array).

group_level=2 returns
{"key":["developer","61fe9c6c226b978f74b76329191806b3"],"value":3000},
{"key":["developer","eb3873f48bb581df13762324b8ec0313"],"value":3500},
{"key":["manager","1"],"value":5000}

Two elements of array are taken into account. In this case, it is the same like group=true, which takes all elements of key array.

What is rereduce for?

As you noticed, reduce function has third parameter rereduce

Result of map function is kept as sorted B-tree. Let's assume we want to summarize some value from each document (tree node). Just like salaries.

First, there are keys and whole nodes (because value of our map function is whole document) passed to reduce function, and rereduce is set to false

Look at the picture, we can reduce branch of the tree into 17, another branch into 4, and third one into 2. Assume each branch has common key at specified group_level (e.g. all people from first branch are developers, second are managers and third are administrators, if group_level is set to 1).

Then reduce function is called again, with following parameters:

function(["developer", "manager", "administrator"], [17, 4, 2], true);

There is common key for whole branch, reduced scalar value for that branch, and rereduce parameter set to true.

Important thing here is to remember that not always values are whole nodes, sometimes it can be already reduced values, and in such case rereduce parameter is helpful to distinguish this situation. In fact, our reduce function wouldn't work for big amount of nodes, because it handles only nodes (only rereduce=false case), not reduced values. To work with a lot of data, we should handle also scalar values:

function(keys, values, rereduce) {
  if (rereduce) {
    return sum(values);
  } else {
    var salaries = 0;
    for(i = 0; i < values.length; i++) {
  }
}

Now it should count and sum all the salaries.

Wednesday, November 18, 2009

Mercurial installation and remote server interaction by hg-login

I want to have mercurial on my machine, but I also want to have "central repository" for continuous integration builds. I chosen mercurial because it is fast (like git), and it has good support in NetBeans (at least I heard it has ;)).
To push/pull changes to/from server, I use hg-login. Ssh is also necessary. Ok, so here are the steps:
1. Install mercurial on both client and server.
apt-get install mercurial
2. Create user mercurial on the server, and disable his shell.
sudo adduser mercurial
Edit /etc/shadow and set his password to "*".
3. Go to server (ssh will suffice) and switch to user mercurial.
sudo su - mercurial
4. Go to /home/mercurial and create repositories directory.
cd /home/mercurial
mkdir repositories
5. Create file hg-login in /home/mercurial. Copy script there. Script can be found on http://mercurial.selenic.com/wiki/HgLogin
mcedit hg-login
It can be necessary to change the script. In my case I needed to change /usr/local/bin/hg to /usr/bin/hg. Change to where your hg command is located.
6. Go back to client machine. Generate ssh keys pair for yourself.
ssh-keygen
Add private key to your ssh agent.
ssh-add
This way when you connect by ssh from client, you are automatically authenticated.
7. Go to server again. In /home/mercurial/.ssh create file authorized_keys.
cd /home/mercurial/.ssh
touch authorized_keys
In this file put line:
command="/home/mercurial/hg-login franek",no-port-forwarding,no-X11-forwarding,no-agent-forwarding [key]
franek is user name. Replace [key] with content of your .ssh/id_rsa.pub file from client. Put whole content there (with ssh-rsa in the beginning and <user>@<host> at the end).
8. Create repository in /home/mercurial/repositories/.
cd /home/mercurial/repositories
mkdir myapplication
cd myapplication
hg init
9. Allow franek to access myapplication repository. In /home/mercurial/repositories create file myapplication.allow. In this file list users who has to have access to myapplication repository. In this case franek, so the file looks like this:
franek
10. On client machine, go to directory where your application is: cd <yourdir>/myapplication
11. Create local mercurial repository.
hg init
12. Add all what is in /myapplication directory to local repository.
hg add
13. Commit added files.
hg commit
You'll need to edit commit comment.
14. Push changes to remote repository.
hg push ssh://mercurial@yourserver/myapplication
While creating this recipe, hg-login site was very helpful.
As I mentioned before, I chosen mercurial because of Netbeans. But I don't find Netbeans support of mercurial satisfactory. I am used to eclipse and it's great support for CVS. In eclipse, if there are some changes in CVS and I don't have them (incoming changes), I can see what has changed (file by file diff) before I update my code. I failed to do this in Netbeans with mercurial.

Tuesday, September 8, 2009

JAVA eXpress in English

JAVA eXpress, Polish magazine about (yes, you guessed it right) Java, from now on is accessible in English. You can get it from http://www.javaexpress.pl/
In this issue:
  • Introduction to Grails
  • Problems of large J2EE applications
  • Graphical Modelling Framework
  • J2ME: Objects Serialization
  • XML in JAVA - XStream Library
  • TeamCity: pre-tested commit
  • Express killers, part III
  • GroovyMag review - June 2009
  • Layering
Check it out and have a nice reading :)

Thursday, August 20, 2009

Google Chrome on Linux with Flash

For some time now I am using Google Chrome. I like it, because it is extremely fast. Quite a blocker for using it as a preferred browser was lack of Flash plugin. Now I have Flash thanks to author of this blog.

All you need to do:
1. Download and extract Adobe Flash player plugin for Firefox
from here. Download 32bit version, even if you are using 64bit linux.
2. Go to
/opt/google/chrome and create directory plugins.
3. Copy
libflashplayer.so to this directory
4. Run google-chrome --enable-plugins

Enjoy :)

Monday, August 10, 2009

Setting up backup by rsync

I want to backup my files on another server. So I go to another server, and create file /etc/rsyncd.conf:

secrets file = /etc/rsyncd.secrets
#Global properties
read only = yes
list = yes
#User on server
uid = backup
#User's group
gid = backup

#Protected share for backups.
[files]
comment = For your eyes only
path = /home/backup/
auth users = franek
read only = no
hosts allow = 192.168.1.64
hosts deny = *
list = yes
We are using user backup as rsync files owner. Don't forget to create him.

So now we need to create entry for franek in rsyncd.secrets:
franek:his_password
rsyncd.secrets cannot be readable for all. In such case rsync daemon will not allow access to protected shares. Set permissions to 600.

We need to do one more thing before starting the daemon. Go to /etc/default/rsync and set RSYNC_ENABLE=true

Ok, issue sudo /etc/init.d/rsync start and rsync deamon is running.

Now go to the client machine. The one we want to make backups from. I want to backup whole /home, so my command looks like this:
sudo rsync -aXAvz --delete --delete-excluded --exclude-from=$DIR/backup.excludes --password-file=$DIR/rsync-pass /home franek@moon::files
So there is sudo rsync, and then some options:
-a the same as -rlptgoD, which is:
-r recurse into directories
-l copy symlinks as symlinks
-p preserve permissions
-t preserve modification times
-g preserve group
-o preserve owner
-D preserve device files, preserve special files
-X preserve extended attributes
-A preserve ACLs
-v be verbose
-z use compression
Then there is --delete and --delete-excluded. It means if there is some file on copy, but there is no such file on source, delete file from copy. --delete-excluded means delete all excluded files from copy.

I keep exclusions patterns in separate file. Format is quite simple:
lost+found
*/.Trash/
*/.thumbnails/
cache/
Cache/
.Cache/
.cache/
My share is password protected. Only user franek can access it, and he needs to give his password. If you want to do it by system (e.g. cron), you don't have the possibility to type the password. However, you can put it into file and make file readable only for user (permissions 700). Then you can just point to that file with --password-file option.

Next there is just source and destination. Just like in cp or smb. Source is pretty simple in my example. Destination is a bit more complicated: <user>@<server>::<share-name>