Return-Path: X-Original-To: apmail-myfaces-dev-archive@www.apache.org Delivered-To: apmail-myfaces-dev-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 5B1FF99B7 for ; Tue, 21 Feb 2012 00:05:24 +0000 (UTC) Received: (qmail 65203 invoked by uid 500); 21 Feb 2012 00:05:24 -0000 Delivered-To: apmail-myfaces-dev-archive@myfaces.apache.org Received: (qmail 65162 invoked by uid 500); 21 Feb 2012 00:05:24 -0000 Mailing-List: contact dev-help@myfaces.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "MyFaces Development" Delivered-To: mailing list dev@myfaces.apache.org Received: (qmail 65155 invoked by uid 99); 21 Feb 2012 00:05:24 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 21 Feb 2012 00:05:23 +0000 X-ASF-Spam-Status: No, hits=-0.5 required=5.0 tests=FREEMAIL_ENVFROM_END_DIGIT,RCVD_IN_DNSWL_LOW,SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (nike.apache.org: domain of lu4242@gmail.com designates 209.85.160.53 as permitted sender) Received: from [209.85.160.53] (HELO mail-pw0-f53.google.com) (209.85.160.53) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 21 Feb 2012 00:05:15 +0000 Received: by pbbrq13 with SMTP id rq13so8072078pbb.12 for ; Mon, 20 Feb 2012 16:04:54 -0800 (PST) Received-SPF: pass (google.com: domain of lu4242@gmail.com designates 10.68.219.70 as permitted sender) client-ip=10.68.219.70; Authentication-Results: mr.google.com; spf=pass (google.com: domain of lu4242@gmail.com designates 10.68.219.70 as permitted sender) smtp.mail=lu4242@gmail.com; dkim=pass header.i=lu4242@gmail.com Received: from mr.google.com ([10.68.219.70]) by 10.68.219.70 with SMTP id pm6mr10159301pbc.120.1329782694777 (num_hops = 1); Mon, 20 Feb 2012 16:04:54 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=mime-version:date:message-id:subject:from:to:content-type; bh=QHFAGGNBehtPobOeXFxUcjl6tC0ebZq+9MMct5WilsU=; b=uQzwaDfw+P3x3wtVCIju1d/DihfelvYocqZVR2Q+8I6C1+jQfAp/Aiw4cJg5UNyjuK M8bIXaHhBn0CYpcfSkOtGNomaP0cQ9+iWfKCs57A+x9jAPZZCwgxmAlHNrOzX/LJzZ0Y GPLxW7WBGNVjqMEcehuz3Wk4I4IBTvCXEb5Q0= MIME-Version: 1.0 Received: by 10.68.219.70 with SMTP id pm6mr8200921pbc.120.1329782694718; Mon, 20 Feb 2012 16:04:54 -0800 (PST) Received: by 10.143.161.8 with HTTP; Mon, 20 Feb 2012 16:04:54 -0800 (PST) Date: Mon, 20 Feb 2012 19:04:54 -0500 Message-ID: Subject: [core] discussion about stateless jsf implementation From: Leonardo Uribe To: MyFaces Development Content-Type: text/plain; charset=ISO-8859-1 X-Virus-Checked: Checked by ClamAV on apache.org Hi I have been studying the proposed code attached to MYFACES-3465. Unfortunately, I have found some issues with the related code that needs to be discussed under dev list. The code has the following drawbacks: - It uses request uri to mark the views instead viewId. This causes when multiple POST are chained with stateless views, a ViewExpiredException is thrown. It is known there's a difference about how myfaces and mojarra deals with viewId, which were clarified in JSF 2.1, with the introduction of ViewHandler.deriveLogicalViewId(). So instead use request uri as the marker, a combination of viewId/deriveLogicalViewId() should be used. - Instead use vdl.buildView() call, it replaces it with com.rits.cloning.Cloner, to duplicate the view and use it on the current request. I think in this case, vdl.buildView() will be faster and more optimal from memory perspective, because we can cache information at Facelet/TagHandler/TagAttribute level like ValueExpressions, attribute values and others, and a deep clone will create unnecessary objects each time. Comparing MyFaces and Mojarra, our implementation of vdl.buildView() is very fast, and for cases when the view is has no dynamic parts it is only built once, so from MyFaces perspective the is not visible difference here (but from Mojarra you can see a difference). This means we don't really need the cache proposed at all. Sometimes less is more. - Some synchronized blocks can slow down performance without need (by thread contention), and I have found other bugs when the code deals with high concurrency. Anyway, the trick is good enough, in cases where you don't want to deal with view state load, even if with the changes done over the time in that part until 2.1.6 have made view state very small. It is an easy way to say to the state manager "... don't save the state for this view ...". After looking the code, I think we could add this as an built-in specific feature for MyFaces Core, rather than a subproject. Anyway, I have an idea that we can do for enhance performance in a significant way. In theory, we can classify JSF views into two groups - static view: views that as an invariant always has the same structure and state once vdl.buildView and render code is called for first time. - dynamic views: views that has some parts that change according to expressions (c:if ....) in vdl.buildView or has programatically added components based on conditions when the render code is called for first time. Also we can classify JSF views into another two groups - stateful: Requires to store some data on the view to work after markInitialState is called. - stateless: Does not require to store anything on the state, because we can duplicate it safely just calling vdl.buildView(). There is a lot of views that on the first request, or in other words, when the view is created by first time and then rendered does not change. The rendered page could change, but the view tree itself do not. Later, on further postbacks, the view state might change for both stateful and stateless views. Here is the trick, if by some way we can make the component tree "thread safe" making it immutable and moving some temporal variables (clientId, rowIndex, dataModel, ...) from the component to FacesContext attribute map, we could use the same view across multiple requests. Then, on a postback (normal submit or ajax), we can build the view as usual. This would involve some changes over UIComponentBase/UIData/UIRepeat internals, to switch between thread-safe or immutable mode and normal mode, and we could expect more calls over FacesContext.getCurrentInstance() because we can't cache FacesContext at UIComponent level, but it will work. A fast proof-of-concept test done shows a big improvement, because we can skip vdl.buildView in some cases and reducing memory usage. Obviously there will be a lot of component that will not support that mode. Anyway, it will not be an easy trick. Suggestions are welcome. regards, Leonardo Uribe