Help! Someone is killing my Tomcat

Today I have a detective story for you. Let’s start with basic information. Victim is well known Tomcat 5.5 server. He lives in a virtual server, with 8 processors and 256 megabytes of memory. There are also several servants living in the house. First of all, there is Debian who does basically all the housekeeping. Then there is native Apache servant who communicates with the outside world. In the cellar lives MySql daemon who keeps all important data.

The main occupation of the Tomcat server is to run my great mvnindex.org project. It is quite easy job. First of all, no one except me is using it. Secondly, the main task of the server is calling the database and returning the results. And of course once per day he has to index the repository.

Even thou his task is simple, sometimes I find Tomcat lying dead. Sometimes he manages to write his last words to his log.

Java HotSpot(TM) Client VM warning: Exception java.lang.OutOfMemoryError occurred dispatching signal SIGTERM to handler- the VM may need to be forcibly terminated

Sometimes he dies without any whisper. At first glance it looks like a natural death caused by lack of heap memory. But there is some circumstantial evidence against this theory. First of all, this mystical sudden death usually happens when there is some visit in the house. For example when I am building new version of the application. Imagine that. I am running mvn clean install command and Tomcat, who is running in a separate process, in separate JVM (1.6.0-b105) under another user suddenly dies. That is strange.

Moreover, adding heap memory using java -Xmx parameter does not help. Sometimes Tomcat lives for several days, sometimes he dies twice per day.

Now you have all the data you need to solve the mystery. Is it a murder? Is it a suicide? Is there a memory leak in the application? Is it a sabotage?

I will not tell you the solution right know. I am sure that someone will solve it in the discussion below. If not, I will publish the solution in few days.

List nebo Iterable?

Dnes budu psát o jedné prkotině, kterou jsme včera řešili s jedním kolegou. Zajímal by mě váš názor na to. Je to opravdu jednoduché. Představte si, že máte následující metodu:

public List<Data> processData(List<Data> data) {
	List<Data> result = new ArrayList<Data>();
	for (Data d:data)
	{
		//do something
	}
	return result;
}

Jak vidíte dostane na vstupu nějaký seznam, ten proiteruje a na základě vstupních dat vrátí nějaký výsledek. Otázka je, jaký typ zvolit pro parametr a potažmo i návratovou hodnotu. Pokud je tato metoda použita na jednom místě není moc co řešit. V našem případě ji ale chceme mít ve veřejném rozhraní. Ba co víc, my počítáme s tím, že programátoři budou vytvářet její různé implementace. Pak už je na místě se pořádně zamyslet. Máme několik možností. Můžeme použít List jako v předchozím případě. Mě by se ale mnohem více líbilo použít Iterable. Samozřejmě můžeme jít zlatou střední cestou a použít Collection.

public Collection<Data> processData(Iterable<Data> data) {
	List<Data> result = new ArrayList<Data>();
	for (Data d:data)
	{
		//do something
	}
	return result;
}

Jaká je ale ta správná volba? Všechno má své pro i proti. Když použiji Iterable, dávám tím jasně najevo, že se argument nechystám nijak měnit, že přes něj chci jenom iterovat. Do metody mohu nacpat jakoukoliv kolekci. Navíc mi to otvírá cestu k tomu, abych použil návrhový vzor Iterator a třeba za pomocí commons-collections nebo Google collections si vstup filtroval. Na druhou stranu mi to může zkomplikovat budoucí implementaci metody. Třeba někdo, kdo bude metodu implementovat, bude chtít zavolat metodu size(). Nebo bude chtít zjistit jestli kolekce obsahuje nějaký prvek. Tím, že v signatuře metody použiji Iterable ho o tuto možnost připravím. Práce s iterátorem je navíc dost nepohodlná.

Když použiji List, tak nebude na první pohled jasné, jestli metoda nebude například do seznamu něco přidávat. Nebude to jasné ani volajícímu, ani implementátorovi. Navíc když budu chtít metodu volat například se Setem, budu ho muset překopírovat do Listu. Já vím, je to na jeden řádek, ale znepřehlední to kód.

Zlatá střední cesta je pravděpodobně nejlepší. Když použiji Collection, zajistím dostatečný komfort jak pro volajícího tak pro implementátora. Sice pořád nebude jasné jestli může být kolekce metodou změněna, ale s tím se asi budeme muset smířit. Navíc nebudeme moci použít vzor Iterator, ale vzhledem k tomu, že ho nikdo beztak nezná, to nebude tak velká škoda.

Zase se dostáváme ke kompromisu, jako všude jinde v programování. Musíme hledat kompromis mezi komfortem a bezpečností, mezi čistotou návrhu a výkonem a nebo jako já, mezi čistotou návrhu a komfortem. V tomto případě je to opravdu jenom prkotina, ale kdo ví, třeba se z ní časem může vyklubat ošklivý problém. A to bohužel ať už zvolíme jakoukoliv variantu.

Simple JDBC template

Občas se mi stane, že nepotřebuji celou tu mašinérii kolem ORM. Chci jenom přistupovat do databáze. Zavolat pár insertů a pár selectů. V té chvíli přichází na řadu JDBC. Je samozřejmě možné používat JDBC přímo, ale jak říká Rod Johnson, je to „sackable offence“. (česky asi důvod k vyhazovu). Zvládnout bez chyby všechny ty try, catche, finally, zavírání connection, result setů a kdoví čeho ještě je jen pro zkušené a velmi disciplinované vývojáře. Spring odjakživa poskytoval rozhranní JdbcTemplate, které krásně usnadňovalo volání JDBC a staralo se o všechnu tu nudnou a nebezpečnou práci se správou zdrojů. Chybělo mi tam ale několik věcí. První z nich bylo pojmenování parametrů jak je známe třeba z HQL. Prostě jsem místo všech těch otazníků v query chtěl psát jména parametrů. Chybělo mi také lepší provázanost s Javou 5 a generiky. (To mi mimochodem dost chybí i u JPA query, která je novější než Java 5).

Nevím jestli se vám to také děje. Já když už umím nějakou technologii, tak se mi občas stane, že mi její zajímavé novinky občas uniknou. Podobně mi uniklo zavedení SimpleJdbcTemplate do Springu 2.0. SimpleJdbcTemplate totiž všechny mé stesky řeší. Nejlépe si to ukážeme na příkladě (ten je převzatý z mého skvělého a nepostradatelného projektu MvnIndex.org, který si teď všichni povinně stáhnete a začnete ho používat, nebo se naštvu a už nikdy nic podobného nenapíšu).

Nejlepší je naimplementovat DAO, které rozšiřuje SimpleJdbcDaoSupport. Tím si ušetříme spoustu práce, stačí nám už jen injektnout do této třídy DataSource. Pak už máme k dispozici SimpleJdbcTemplate a můžeme si dovolit například takovéto volání:



  public List<BasicArtifactInfo> searchArtifacts(String searchExpression, PagingInfo pagingInfo) {
    Map<String,Object> args = new HashMap<String, Object>();
    args.put("searchExpression""%"+searchExpression+"%");
    args.put("from", pagingInfo.getFrom());
    args.put("size", pagingInfo.getSize());
    return getSimpleJdbcTemplate().query(
          "select distinct group_id, artifact_id from ARTIFACT where artifact_id like :searchExpression or group_id like :searchExpression order by if(group_id like :searchExpression, 0, 1), group_id, artifact_id limit :from, :size"
          BASIC_ARTIFACT_INFO_MAPPER , 
          args);
  }

Vidíme že atributy dotazu dáme jednoduše do mapy, zavoláme dotaz, poskytneme mapovač výsledků a je to. V dotazu můžeme použít jména parametrů stejně jako to známe z HQL. Takže můžeme například psát „... where artifact_id like :searchExpression or group_id like :searchExpression...“. Pro mapování výsledků musíme implementovat jednoduché rozhraní ParameterizedRowMapper.



  private static final ParameterizedRowMapper<BasicArtifactInfo> BASIC_ARTIFACT_INFO_MAPPER = new ParameterizedRowMapper<BasicArtifactInfo>(){
    public BasicArtifactInfo mapRow(ResultSet rs, int rowNumthrows SQLException {
      return new BasicArtifactInfo(rs.getString("group_id"), rs.getString("artifact_id"));
    }
  };

Vidíme, že generika jsou tu plně podporována, takže si nemusíme dělat hlavu s přetypováváním, varováními překladače atp. Super ne? A to jsem zapomněl na to hlavní. Spring se mi postará o vytvoření PreparedStatementů, správu transakcí, mapování vyjímek a prostě o všechno na co jsme od něj zvyklí.

Takže pokud je pro vás Hibernate moc těžkopádný a nechcete se učit iBatis, pokud chcete jen volat JDBC, zkuste se podívat na SimpleJdbcTemplate, stojí to za to.

Celou třídu si můžete prohlédnout v SVN.