[ 
https://issues.apache.org/jira/browse/JCR-3453?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13486993#comment-13486993
 ] 

Stefan Guggisberg commented on JCR-3453:
----------------------------------------

bq. Actually I'm ready to contribute this enhancement to Jackrabbit.

excellent!

bq. If you could modify my attached repository.xml file so that it use 
Oracle9FileSystem & Oracle9PersistenceManager and certify that that 
configuration is going to work on Oracle 11gR2, I'd like to change this ticket 
to improvement.

sorry, i have neither the time nor an oracle install at hand.
                
> Jackrabbit might deplate the temporary tablespace on Oracle
> -----------------------------------------------------------
>
>                 Key: JCR-3453
>                 URL: https://issues.apache.org/jira/browse/JCR-3453
>             Project: Jackrabbit Content Repository
>          Issue Type: Bug
>          Components: jackrabbit-core
>    Affects Versions: 2.1.2, 2.5.2
>         Environment: Operating system: Linux
> Application server: Websphere v7
> RDBMS: Oracle 11g
> Jackrabbit: V2.1.2 (built into Liferay 6.0 EE SP2)
>            Reporter: Laszlo Csontos
>         Attachments: repository.xml
>
>
> *** Experienced phenomenon ***
> Our customer reported an issue regarding Liferay’s document library: while 
> documents are being retrieved, the following exception occurs accompanied by 
> temporary tablespace shortage.
> [9/24/12 8:00:55:973 CEST] 00000023 SystemErr     R ERROR 
> [org.apache.jackrabbit.core.util.db.ConnectionHelper:454] Failed to execute 
> SQL (stacktrace on DEBUG log level)
> java.sql.SQLException: ORA-01652: unable to extend temp segment by 128 in 
> tablespace TEMP
> at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:440)
> at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396)
> …
> at 
> oracle.jdbc.driver.OraclePreparedStatementWrapper.execute(OraclePreparedStatementWrapper.java:1374)
> at 
> com.ibm.ws.rsadapter.jdbc.WSJdbcPreparedStatement.pmiExecute(WSJdbcPreparedStatement.java:928)
> at 
> com.ibm.ws.rsadapter.jdbc.WSJdbcPreparedStatement.execute(WSJdbcPreparedStatement.java:614)
> …
> at 
> org.apache.jackrabbit.core.util.db.ConnectionHelper.exec(ConnectionHelper.java:328)
> at 
> org.apache.jackrabbit.core.fs.db.DatabaseFileSystem.getInputStream(DatabaseFileSystem.java:663)
> at 
> org.apache.jackrabbit.core.fs.BasedFileSystem.getInputStream(BasedFileSystem.java:121)
> at 
> org.apache.jackrabbit.core.fs.FileSystemResource.getInputStream(FileSystemResource.java:149)
> at 
> org.apache.jackrabbit.core.RepositoryImpl.loadRootNodeId(RepositoryImpl.java:556)
> at org.apache.jackrabbit.core.RepositoryImpl.<init>(RepositoryImpl.java:325)
> at org.apache.jackrabbit.core.RepositoryImpl.create(RepositoryImpl.java:673)
> at 
> org.apache.jackrabbit.core.TransientRepository$2.getRepository(TransientRepository.java:231)
> at 
> org.apache.jackrabbit.core.TransientRepository.startRepository(TransientRepository.java:279)
> at 
> org.apache.jackrabbit.core.TransientRepository.login(TransientRepository.java:375)
> at 
> com.liferay.portal.jcr.jackrabbit.JCRFactoryImpl.createSession(JCRFactoryImpl.java:67)
> at com.liferay.portal.jcr.JCRFactoryUtil.createSession(JCRFactoryUtil.java:43)
> at com.liferay.portal.jcr.JCRFactoryUtil.createSession(JCRFactoryUtil.java:47)
> at com.liferay.documentlibrary.util.JCRHook.getFileAsStream(JCRHook.java:472)
> at 
> com.liferay.documentlibrary.util.HookProxyImpl.getFileAsStream(HookProxyImpl.java:149)
> at 
> com.liferay.documentlibrary.util.SafeFileNameHookWrapper.getFileAsStream(SafeFileNameHookWrapper.java:236)
> at 
> com.liferay.documentlibrary.service.impl.DLLocalServiceImpl.getFileAsStream(DLLocalServiceImpl.java:192)
> The original size of tablespace TEMP used to be 8Gb when the error has 
> occurred for the first time. Later on it was extended by as much as 
> additional 7Gb to 15Gb, yet the available space was still not sufficient to 
> fulfill subsequent requests and ORA-01652 emerged again.
> *** Reproduction steps ***
> 1) Create a dummy 10MB file
> $ dd if=/dev/urandom of=/path/to/dummy_blob bs=8192 count=1280
> 1280+0 records in
> 1280+0 records out
> 10485760 bytes (10 MB) copied, 0.722818 s, 14.5 MB/s
> 2) Create a temp tablespace
> The tablespace is created with 5Mb and automatic expansion is intentionally 
> disabled.
> SQL> CREATE TEMPORARY TABLESPACE jcr_temp
>       TEMPFILE '/path/to/jcr_temp_01.dbf'
>       SIZE 5M AUTOEXTEND OFF;
> Table created.
> SQL> ALTER USER jcr TEMPORARY TABLESPACE jcr_temp;
> User altered.
> 3) Prepare the test case
> For the sake of simplicity a dummy table is created (similar to Jackrabbit's 
> FSENTRY).
> SQL> create table FSENTRY(data blob);
> Table created.
> SQL>
> CREATE OR REPLACE PROCEDURE load_blob
> AS
>     dest_loc  BLOB;
>     src_loc   BFILE := BFILENAME('DATA_PUMP_DIR', 'dummy_blob');
> BEGIN
>     INSERT INTO FSENTRY (data)
>         VALUES (empty_blob())
>         RETURNING data INTO dest_loc;
>     DBMS_LOB.OPEN(src_loc, DBMS_LOB.LOB_READONLY);
>     DBMS_LOB.OPEN(dest_loc, DBMS_LOB.LOB_READWRITE);
>     DBMS_LOB.LOADFROMFILE(
>           dest_lob => dest_loc
>         , src_lob  => src_loc
>         , amount   => DBMS_LOB.getLength(src_loc));
>     DBMS_LOB.CLOSE(dest_loc);
>     DBMS_LOB.CLOSE(src_loc);
>     COMMIT;
> END;
> /
> Procedure created.
> SQL> EXEC load_blob();
> PL/SQL procedure successfully completed.
> 4) Execute the query
> SQL> select nvl(data, empty_blob()) from FSENTRY;
> ERROR: ORA-01652: unable to extend temp segment by 128 in tablespace JCR_TEMP
> 4) Let’s see how temporary tablespace is being used
> Query the size of the original LOB data.
> SELECT s.segment_name,
>        s.segment_type,
>        SUM(s.blocks) AS blocks
>   FROM dba_segments s,
>        (SELECT segment_name, index_name
>           FROM dba_lobs l
>          WHERE l.table_name = 'FSENTRY'
>            AND l.column_name  = 'DATA') ls
>  WHERE s.segment_name = ls.segment_name
>     OR s.segment_name = ls.index_name
>  GROUP BY s.segment_name, s.segment_type;
> SEGMENT_NAME                SEGMENT_TYPE      BLOCKS
> ---------------------------------------------------------------------------
> SYS_LOB0000035993C00001$$   LOBSEGMENT        1408
> SYS_IL0000035993C00001$$    LOBINDEX             8
> Query the size of the temporarily created LOB data.
> SELECT s.sql_text, t.segtype, t.blocks
>   FROM v$sql s, v$tempseg_usage t
>  WHERE s.sql_id = t.sql_id;
> SQL_TEXT                                        SEGTYPE      BLOCKS
> ---------------------------------------------------------------------------
> select nvl(data, empty_blob()) from lobtest     LOB_DATA     1408  (~11 Mb)
> select nvl(data, empty_blob()) from lobtest     LOB_INDEX     128  (~1 Mb)
> LOB index might need some explanation: it's an internal structure that is 
> strongly associated with LOB storage (LOB locators point to the top of the 
> LOB index tree, where leaf blocks point to the actual LOB chunks). The bottom 
> line is that a user may not drop/alter/rebuild LOB indexes in any way.
> As a conclusion we can see here that a temporary LOB has been been created by 
> Oracle indeed and its space requirements are quite similar to the original 
> one.
> *** Analysis ***
> The aforementioned exception is thrown in the getInputStream(...) method of 
> class org.apache.jackrabbit.core.fs.db.DatabaseFileSystem while it’s 
> attempting to execute that SQL statement which is denoted by selectDataSQL.
> Based on this particular case, customer has the Jackrabbit repository 
> configured to use org.apache.jackrabbit.core.fs.db.OracleFileSystem, which 
> implies that the actual value of selectDataSQL is the following.
> SELECT NVL(FSENTRY_DATA, empty_blob())
>   FROM J_FSASSSA_1LIFERAYFSENTRY
>  WHERE FSENTRY_PATH  = :1
>    AND FSENTRY_NAME    = :2
>    AND FSENTRY_LENGTH IS NOT NULL
> The most important point here is that Oracle creates temporary LOBs, if LOB 
> columns are used in SQL functions. From the point of view of Oracle, it’s a 
> completely logical behaviour, since it has to evaluate the given expression 
> and during doing so the database manager also has to store the result of that 
> calculation.
> In this case, if column FSENTRY_DATA is null an empty LOB locator is created, 
> however it’s unclear why it is functionally required. Interestingly other 
> database file system implementations (eg. for DB2) do not use an equivalent 
> SQL function at the same place (eg. COALSCE in case of DB2), but they return 
> FSENTRY_DATA directly without performing such a pre-processing.
> The second part of the experienced problem is that according to the Oracle 
> 11g Database SecureFiles and Large Objects Developer's Guide, if a temporary 
> LOB has been returned to the application, it’s the caller (except PL/SQL 
> program blocks) responsibility to explicitly free the received object. Having 
> this in mind, handling temporary LOBs in a decent way can be accomplished by 
> checking and freeing them manually.
> void someMethod() {
>   ...
>   ResultSet rs = ...
>   oracle.sql.BLOB data = (oracle.sql.BLOB) rs.getBlob(...);
>   if (data.isTemporary()) {
>     data.freeTemporary();
>   }
>   ...
> }
> Apparently org.apache.jackrabbit.core.fs.db.OracleFileSystem does not take 
> care of disposing temporary LOBs and temporary tablespace is being depleted 
> this way in a long run.
> *** Conclusion ***
> Jackrabbit definitely should at least free temporary LOBs in OracleFileSystem 
> or avoid using the NVL function completely and moving that logic to the 
> application instead, would make the whole phenomenon cease to exist.

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira

Reply via email to