High Volume Server
High Volume Server
High Volume Server
High-Volume Server
Version 16.7
Development Guide
Legal Notice
Preface ................................................................................................................................ 7
3
Table of Contents
4
Table of Contents
Split_partition .............................................................................................. 72
Merge_partition ........................................................................................... 72
Switch_out ................................................................................................... 73
Switch_in ..................................................................................................... 73
Oracle installations ....................................................................................... 73
Switch in and switch out partitions ................................................................ 74
Chapter 9 Sample Program for Generating Metadata for Partition Exchange .............. 93
5
Table of Contents
List of Tables
6
Preface
This document describes the fundamental features and behaviors of High-Volume Server. It provides
an overview and then discusses the basic features of High-Volume Server in detail.
IMPORTANT
Documentum Content Server is now OpenText Documentum Server. OpenText Documentum Server
will be called Documentum Server throughout this guide.
Intended Audience
This document is written for system and repository administrators, application programmers, and
any other user who wishes to obtain an understanding of the services and behavior of High-Volume
Server. The document assumes that the reader has an understanding of Documentum Server,
relational databases, object-oriented programming in Java, and SQL (Structured Query Language).
Conventions
This document uses the following conventions in the syntax descriptions and examples.
Syntax conventions
Convention Identifies
italics A variable for which you must provide a value.
[ ] square brackets An optional argument that may be included only once
{ } curly braces An optional argument that may be included multiple times
| vertical line A choice between two or more options
( ) parentheses Parentheses are not syntax indicators, but must be typed
exactly as shown in the syntax descriptions.
7
Preface
Revision History
Revision Date Description
October 2019 Initial publication.
8
Chapter 1
Documentum High-Volume Server
Overview
9
Documentum High-Volume Server Overview
10
Chapter 2
Batch Operations
Documentum Server includes a batch mode that can increase the server performance when creating
objects. Batch mode delays adding data to the RDBMS until the batch is flushed or committed,
instead of adding it for each operation.
Batch operations
Batch operations can increase performance for some applications that add groups of objects. When
you add a repository object, there is a certain amount of overhead associated with adding the data in
the database tables representing the new object. Using batch mode in Documentum Server, multiple
items are not added to the RDBMS server until the batch is flushed. This means that the database
set up and row locking and unlocking apply to all the objects in the batch as a whole. You gain
performance improvements by handling these operations in a batch. You also gain a transactional
benefit. Until the batch is committed or closed, the batch can be aborted and the changes rolled
back to any previous commit. Every batch represents a transaction. When you open a batch, a
transaction implicitly begins.
To support this mode, DFC has been enhanced with the addition of a batch manager to control batch
operations. Methods defined for the batch manager are: open, flush, commit, abort, and close batches.
When a batch is opened, Documentum Server caches operations that modify the RDBMS until the
batch is flushed. When flushed, the operations are performed in the database at that time. The batch
continues to cache operations until the next flush. Calls to commit flush the cache, and commit the
outstanding operations in the database. Calls to abort roll back the operations in the database to the
last commit. Calls to close flush the cache, commit the outstanding operations in the database, and
close the batch.
When you open a batch, you can choose to open a simple batch, or open a batch with groups. If an
error occurs when the first type of batch is committed, none of the actions in the batch commit to the
database. All of those items roll back out of the database and Documentum Server. If you open a
batch with groups, if there is an error for an item in a group, only the members of that group roll
back. The other groups without errors commit. Additionally, for a batch opened with groups, you
can retrieve information about which actions failed and caused the rollback. You control whether to
use groups by choosing the corresponding open batch call, openBatchGroup. The methods defined
for the batch manager that work with groups are: openBatchGroup, newGroup, getGroups, and
getFailedGroups. The IDfBatchGroup interface is used to examine batch groups.
An extension to transactions has been added that supports nested transactions. The earlier transaction
mechanism did not allow nested transactions. Since the batch mode works like a transaction (in that
11
Batch Operations
it can be rolled back before it is committed), it was necessary to build in a transaction method that
allowed nested transactions. A batch of operations can contain transactions, since the transaction
used by the batch manager allows for nested transactions.
IDfBatchManager
This interface provides control of the batch operation. A batch cannot be nested, so only one batch
can be open at a time. Typically, you would open a batch, perform many operations, and close the
batch. Other methods, flush and commit, provide more control of operations during the batch. The
group methods allow you to examine any failed transactions, and allow contain any batch failures to
that particular group. The batch manager supports the following methods:
• void openBatch (int size, boolean flushBatchOnQuery, boolean oneAuditPerBatch, boolean
oneEventPerBatch, Properties options) throws DfException. This method opens a batch and sets
the batch attributes.
This method uses the following parameters:
— size (batch size) is a hint to the server cache for the number of objects to create in the batch
before flushing it. Since each type is related to several tables and repeating attributes require
multiple rows, the mapping between the batch size and the number of objects created before
flushing is only approximate. The server uses the batch size to determine the size of the cache
to hold the tables for the objects.
— flushBatchOnQuery sets whether the server must flush the batched tables when a query is
issued during the batch. This flag can be overridden by an individual query by using the
IDfQuery.setFlushBatchOnQuery method.
— oneAuditPerBatch sets whether the server generates one audit trail for the batch or one
audit trail per object insertion. The server will only honor this flag if the caller has audit
configuration privileges.
12
Batch Operations
— oneEventPerFlush sets whether the server generates one event for the batch or one event per
object insertion. Use this to reduce the number of events generated during object creation.
— options contains a set of hints to the server. Currently, there is only one, driver=bcp. The server
will ignore the options it does not support.
• void openBatch() throws DfException. This method is a special case of the earlier one. It opens a
batch with the default batch size, with flushBatchOnQuery set to true, oneAuditPerBatch flag set
to false, and oneEventPerBatch flag set to false. The default batch size can be set in dfc.properties
by using the dfc.batchmanager.max_batch_size parameter.
• void openBatchGroup(int size, boolean flushBatchOnQuery, boolean oneAuditPerBatch, boolean
oneEventPerBatch, String ignoreInsertError) throws DfException. Opens a batch with groups.
When a batch is opened with this method, errors caused by data (for example, constraint
violations), are kept within the batch manager. All the data from a group that contains that bad
data will be removed; only groups without errors in the data will be committed into repository.
The client will get an error report about the failures only after the batch commit. Those errors
will not interrupt the client operations. Other failures will still be reported back to client
synchronously. Batch manger also starts to combine all object creation and row inserts into a
collection. Any failure in the collection will cause all data in the collection to be removed from the
repository. Most of the parameters are described in the openBatch method, except for:
— ignoreInsertError is a comma separated list of registered tables. Insert errors from these tables
will be ignored, but errors from tables not in the list will roll back the batch transaction.
• void newGroup() throws DfException. Tells the batch manager to close the current group and
open a new group. Nothing happens if the batch was not opened with a group.
• List<IDfBatchGroup> getGroups(). Gets a list of all the groups in the current transaction. The
commitBatch and closeBatch methods clear the group information.
• List<IDfBatchGroup> getFailedGroups(). Gets a list of the groups that have errors and were
removed from the batch. This method returns null if there are no errors. You can retrieve
attributes of the failed objects, but because the objects have been removed from the repository, all
save operations will fail. You should treat these objects as read-only. The result of this call is only
valid after commitBatch(). Any insert after the commitBatch() call will reset the error from the
previous commitBatch(). You should call the method immediately after commitBatch().
• void flushBatch() throws DfException. This method flushes the batch's data in the server cache to
the database. This clears the cache, but until the batch is committed, the data is not available to
other sessions. This method does not affect grouping.
• void commitBatch() throws DfException. This method flushes the batch's data in the server cache
to the database and then commits the transaction. Essentially, this is equivalent to issuing a
closeBatch() call followed by an openBatch() call. If there is a group, the current group will be
closed and a new one will be opened.
• void abortBatch() throws DfException. This method clears up any outstanding entries in the batch,
rolls back the transaction to the status right after the previous commitBatch, and closes the batch.
• void closeBatch() throws DfException. This method flushes the batch's data in the server cache to
the database, commits the transaction, and then closes the batch.
• boolean isOneAuditPerBatch (). This method indicates whether there is one audit trail generated
for the batch per batch size.
13
Batch Operations
• boolean isOneEventPerBatch(). This method indicates whether there is only event notification
(queue item) generated for the batch per batch size.
• boolean isBatchActive(). This method indicates whether the current session or session manager
has turned on the batch mode, in other words, if there is an active batch.
• boolean isFlushBatchOnQuery(). This method indicates whether the server needs to flush the
batched tables if a query is issued during the batch.
• int getMaxBatchSize(). This method returns the batch size.
If either of the openBatch methods is called while isBatchActive is true, the DFC_BATCHMANAGER
_BATCH_IN_PROGRESS exception will be thrown.
IDfBatchGroup
Use the following methods to examine items in the group. If the group was retrieved by using the
getFailedGroups method, you should treat the objects as read-only. If the batch is committed or
closed, the group information is cleared.
• Collection<IPersistentObject> getObjects(). Returns the newly created objects in a group.
• List<String> getInsertStmt(). Returns the insert statements for registered tables.
• List<IPersistentObject> getFailedObjects(). Returns the error messages for the failed objects.
IDfLocalTransaction
An IDfLocalTransaction object is the handle to a nestable transaction. It is used with methods from
IDfSession.
IDfSession
For batch operations, there are new methods added to the IDfSession interface. Unlike existing
transaction methods, the new transaction methods can be nested. IDfSession supports the following
new methods:
• IDfLocalTransaction beginTransEx() throws DfException. This method begins a transaction and
returns a IDfLocalTransaction object. This method supports nested transactions, and internally
uses a transaction stack to keep track of the current transactions.
• void abortTransEx(IDfLocalTransaction tx) throws DfException. This method checks if the
transaction is on the stack. If so, the transaction is rolled back (aborted) and if there is any open
batch or transaction above the transaction on the transaction stack, that batch is also aborted.
Otherwise, if the transaction is not on the stack, a DFC_WRONG_TRANSACTION_SCOPE
exception will be thrown.
14
Batch Operations
IDfQuery
The method added to IDfQuery allows a client to override the flag set by the IDfBatchManager on a
per query basis. IDfQuery supports the following new method:
• void setFlushBatchOnQuery(boolean flushBatch)
This method specifies whether this query will cause the open batch to flush. Since the batch caches
the inserted data, the batch must flush the data so that query can return the changes made in the
batch. When set to true, the batch will flush the data whenever there is a query on the type or table
that is in the batch. If the caller knows that a query result is not in the data in the batch (or doesn't
care about the data currently in the batch), set the flag to false to avoid an unnecessary batch flush.
This method allows clients to override the flushBatchOnQuery flag set in the IDfBatchManager on
a per query basis. If not set, the query will use the flag set in the batch manager.
IDfAuditTrailManager
IDfEventManager
This new interface and method is added to support event notification to be used by the full-text
engine. During batch insert, multiple events will be written into one queue item if oneEventPerBatch
is specified.
• List<IDfPair<IDfId,String>> parseBatchedIds(IDfId eventId) throws DfException. This method
will parse the ID list value in an event specified by the eventId and return an IDfList with the list
of pairs <IDfId, String> for each object ID and the operation applied to it.
Batch example
The following example is a basic DFC Java program that uses a loop to create some objects. The loop
is surrounded by calls to openBatch() and closeBatch(). Just using this simple enhancement to a client
can provide modest performance gains. The batch code is relative easy to add to current applications.
The following is a snippet from the example program that sets up, opens, and closes the batch:
15
Batch Operations
import com.documentum.fc.client.IDfBatchManager;
...
bMgr = session.getBatchManager();
bMgr.openBatch();
// Batched client operations
...
bMgr.closeBatch();
The following is a simple standalone example program demonstrating batching. Be sure to have a
copy of dfc.properties in the classpath for the program:
/*
* StdBatchingExample.java
* This example assumes that you have a standard type, "test_payment_check"
* already created. One way to create this type is to use the following
* DQL statement:
CREATE TYPE "test_payment_check" (
account integer,
check_number integer,
transaction_date date,
amount float,
bank_code integer,
routing integer
) WITH SUPERTYPE "dm_document" PUBLISH
*
* This example also assumes that there is a check image GIF file in the
* working directory (use any GIF to stand in for a check image), and that
* the repository name, username, and password are passed to the program
* on the command line.
*/
import com.documentum.com.DfClientX;
import com.documentum.com.IDfClientX;
import com.documentum.fc.client.IDfClient;
import com.documentum.fc.client.IDfSession;
import com.documentum.fc.client.IDfSessionManager;
import com.documentum.fc.client.IDfBatchManager;
import com.documentum.fc.client.IDfSysObject;
import com.documentum.fc.common.*;
public class StdBatchingExample {
public void begin(String username, String password, String docbaseName) {
IDfClientX clientx;
IDfClient client;
IDfSession session = null;
IDfSessionManager sMgr = null;
IDfBatchManager bMgr = null;
IDfSysObject sysObj;
try {
//create a Client object
clientx = new DfClientX();
client = clientx.getLocalClient();
16
Batch Operations
sysObj.save();
}
// Close Batch and commit objects to repository
bMgr.closeBatch();
}
catch(Throwable e) {
if(e instanceof DfException) {
System.out.println("DFC Exception:");
String s = ((DfException)e).getStackTraceAsString();
System.out.println(s);}
else {
System.out.println("Non-DFC Exception");
e.printStackTrace();
}
}
finally {
if (session != null)
sMgr.release(session);
}
}
public static void main(String[] args)
throws java.lang.InterruptedException {
String docbase = args[0];
String user = args[1];
String password = args[2];
new StdBatchingExample().begin(user, password, docbase);
}
}
17
Batch Operations
18
Chapter 3
Currency Scoping
Documentum Server currency scoping is a feature that controls object currency checking by using a
scope manager. When objects are fetched or queries are run, they are saved temporarily for use by
the client. How long a object or query can be used until it has to be refetched or rerun is managed
by currency checking.
Currency scoping
Another Documentum Server feature is control over object currency checking by using a scope
manager. When objects are fetched or queries are run, they are saved temporarily for use by the
client. How long a object or query can be used until it has to be refetched or rerun is managed by
currency checking. Objects and queries that do not change for the duration of a transaction, batch,
or section of a client code will not be refetched, and are good candidates to benefit from currency
scoping. The scope manager controls the checking of object currency, so that objects are checked once
during the currently defined scope. The assumption is that the object or query will not change during
the scope. This reduces the RPC communication traffic between DFC and Documentum Server
and reduces redundant policy checks on objects.
19
Currency Scoping
Methods to access the scope manager have been added to the following interfaces:
• IDfSession
• IDfSessionManager
A new enumerated type has also been added:
Enum ScopeBoundary
{
OPERATION,
TRANSACTION,
BATCH,
CUSTOM
}
IDfScopeManager and its methods control the currency scoping for each of the sessions managed
by IDfSessionManager. Each session manager has one scope manager. The IDfScopeManager
sets the scope boundaries for all the sessions of that session manager. Within a session, the
IDfSessionScopeManager can set custom scope boundaries for that individual session.
Initially, no scope boundaries are set. After you set a scope boundary, a scope is pushed onto the
scope stack when program execution crosses that boundary. For example, if you set TRANSACTION
and BATCH scope boundaries, then scopes are pushed onto the stack whenever a transaction or a
batch is entered. For query or object fetches set for CURRENCY_CHECK_ONCE_PER_SCOPE,
the time is compared with that of the current scope's timestamp on the stack. If the query or fetch
occurred since the current scope's timestamp, then the cached version is used. When the current
scope boundary is exited, the scope is popped from the scope stack.
There are four possible scope boundaries, OPERATION, TRANSACTION, BATCH, and CUSTOM.
The CUSTOM boundaries are set by using the beginScope() and endScope() methods in either the
IDfScopeManager or the IDfSessionScopeManager interface.
It is possible for one currency scope to be opened inside of another. For example, if BATCH and
TRANSACTION boundaries are set, and you begin a batch and then begin a transaction there is a
TRANSACTION scope in the BATCH scope. You can control how the scope timestamp is set when
a scope is opened inside another, either setting a new timestamp or using the timestamp of the
enclosing scope. If you set the bNested parameter to true, a new timestamp is set for the scope; if you
set bNested to false, the timestamp of the enclosing scope is used for the new scope.
Currency scoping can also be enabled on the server side. Just like the client-side scoping, server-side
scoping can improve performance, especially for queries and objects that will remain current while
the client application is executing. Many server-side operations have been optimized to be able to
take advantage of server-side currency scoping. As a developer, your only control is to enable or
disable server-side scoping. However, different sessions created with the session manager can have
different values. After changing the value of the enable parameter, subsequent sessions will have the
new value. In most cases, you should enable server side scoping to improve performance.
20
Currency Scoping
IDfScopeManager
IDfScopeManager declares the following public methods. Each session manager will have one
instance of IDfScopeManager. Scopes defined by the scope manager are effectively templates to
create scopes on sessions that belong to the session manager of a scope manager instance.
• void setDefaultScope(ScopeBoundary boundary, boolean bNested) throws DfException
Sets a scope boundary and defines whether to set a new timestamp when the boundary is crossed.
The choices for scope boundary are OPERATION, TRANSACTION, or BATCH:
— OPERATION—The boundary is the execution of an IDfOperation method.
— BATCH—The boundary is the batch transaction existing between calls to openBatch and to
either commitBatch, closeBatch, or abortBatch.
— TRANSACTION—The boundary is entered during a call to beginTrans or beginTransEx, or
can also be entered when a session is created through the session manager (if a transaction was
started in the session manager with beginTransaction and the session is being created on the
same thread that called beginTransaction). The TRANSACTION boundary begins when the
session enters a transaction and ends when the transaction is committed or aborted.
If bNested is false, the timestamp of the scope is inherited from the outer parent scope. Otherwise,
the timestamp is the current time. Nested custom scopes are not supported by the scope manager
(but are supported by the session scope manager). You cannot reset a scope if there are sessions
that have the corresponding scope active. For example, if the TRANSACTION scope boundary is
set when a session begins a transaction, that session will have an active scope based on that default
scope. Until the session aborts or commits the transaction, thereby ending the scope, the default
scope of TRANSACTION cannot be changed. This applies to all sessions of the session manager.
• IDfScope getDefaultScope(ScopeBoundary boundary)
Returns the default scope template for the specified boundary.
• IDfScope clearDefaultScope(ScopeBoundary boundary)
Removes the scope boundary. A new scope will not be entered when program execution crosses
the boundary. This undoes the effect of the setDefaultScope() method. You cannot remove a scope
boundary when there are sessions that have the corresponding scope active.
• IDfScope beginScope(boolean bNested) throws DfException
Creates an explicit CUSTOM scope boundary to be applied to future sessions created through
the session manager. If bNested is false, the timestamp of the scope is inherited from the outer
parent scope. Otherwise, the timestamp is the current time. The scope manager does not support
nested custom scopes; an exception is thrown if a custom scope already exists (the session scope
manager does support nested scopes). If server scoping is enabled, and bNested is TRUE, the
CUSTOM scope is pushed to the server.
• void endScope() throws DfException
Close the current custom scope (as returned by the getCurrentScope() method). For each session
whose current scope is this CUSTOM scope being closed, a call is made to popScope on that
session. If any session has this custom scope on its stack but it's not the current scope, an exception
is thrown and no action is taken on any sessions.
• boolean isScopeActive()
21
Currency Scoping
Returns true if an explicit CUSTOM scope has been opened with the beginScope method.
• void enableServerScoping(boolean enable) throws DfException
Enable or disable server side scoping based on the value of the parameter. The value is propagated
to each session scope manager as sessions are created through the session manager.
• boolean isServerScopingEnabled()
Returns TRUE if server side scoping is enabled.
• IDfScope getCurrentScope()
This method returns the most recently created scope.
• int getScopeCount()
Returns the number of elements on the scope stack.
• void clearScopes() throws DfException
For each custom scope defined by this scope manager, a call is made to pop the scope off the stack
for each session which has that scope as its current scope. If a TRANSACTION scope is defined
by this scope manager (as a result of having opened a transaction with beginTransaction), no
action is taken and an exception is thrown.
IDfSessionScopeManager
IDfSessionScopeManager declares methods that an application will use to access scopes from
sessions. Each session has an instance of IDfSessionScopeManager.
• IDfScope beginScope(boolean bNested) throws DfException
This method will create an explicit custom scope and push it onto the stack. This scope is local
to the session and is closed by calling endScope. If bNested is false, the timestamp of the scope
is inherited from the outer parent scope. Otherwise, the timestamp is the current time. Nested
custom scopes are supported by the session scope manager (but not the scope manager).
• void endScope() throws DfException
Pops the current custom scope off the stack. An exception is thrown if the current scope is not a
custom scope or if the current scope is an explicit custom scope, or a TRANSACTION, BATCH, or
OPERATION scope defined by the scope manager on the session manager.
• boolean isScopeActive()
Returns true if an explicit CUSTOM scope has been opened with the beginScope method.
• void enableServerScoping(boolean enable) throws DfException
Enable or disable server side scoping based on the value of the parameter. This value is applied
to all new scopes created on this session. An exception is thrown if the server does not support
scoping.
• boolean isServerScopingEnabled()
Returns TRUE if server side scoping is enabled.
• IDfScope getCurrentScope()
22
Currency Scoping
Returns the top element of the scope stack or NULL if the stack is empty.
• int getScopeCount()
Returns the number of elements on the scope stack.
• void clearScopes() throws DfException
Pops all the scopes on the scope stack. If any scopes on the stack were defined by the scope
manager on the session manager, an exception is thrown and no action is taken.
IDfScope
The member methods in the Scope class are listed below. After you set a scope boundary, a scope is
pushed onto the scope stack whenever program execution crosses that boundary. When the current
scope boundary is exited, the scope is popped from the scope stack. The scope object contains the
ScopeBoundary, the timestamp, and the bNested values for that scope.
• ScopeBoundary getBoundary()
Returns the current operation's scope boundary value. The values of the enum ScopeBoundary
are: OPERATION, TRANSACTION, BATCH, and CUSTOM.
• long getTimeStamp()
Returns the current timestamp.
• boolean isCurrent(long timeStamp)
Returns whether the timestamp passed in, typically representing the last checked timestamp
of an object or a query, is current.
• boolean isNested()
Returns whether the scope is nested or not. If isNested() returns TRUE, the current scope used
the then current time for its timestamp; if isNested() returns FALSE, the current scope took its
timestamp from the enclosing scope.
IDfSessionManager
IDfSession
23
Currency Scoping
In the example, the scope boundary is cleared after the transaction, but could be left in place. If not
cleared, a new scope would be created if another transaction were entered later.
Similarly, to set the scope boundary to batch, use the following code:
IDfBatchManager bMgr = null;
...
sMgr.getScopeManager().setDefaultScope(ScopeBoundary.BATCH, true);
bMgr.openBatch();
//client batch operations
...
bMgr.closeBatch();
sMgr.getScopeManager().clearDefaultScope(ScopeBoundary.BATCH);
As in the previous code snippet, the scope boundary is cleared after the batch, but could be left in
place. If not cleared, a new scope would be created if another batch were entered later.
Finally, to set a custom scope boundary, use the following code:
session = sMgr.getSession(docbaseName);
...
session.getSessionScopeManager().beginScope(true);
//client operations
...
session.getSessionScopeManager().endScope();
Notice that the custom scope on the current session is set using the Session Scope Manager. If the
Scope Manager is used to set a custom scope, the scope begins when a new session is created by the
Session Manager associated with the Scope Manager.
The following is a simple stand-alone example program demonstrating currency scoping. Be sure to
have a copy of dfc.properties in the classpath for the program:
24
Currency Scoping
/*
* StdScopingExample.java
*
*
* This example assumes that you have a standard type "test_payment_check"
* already created. One way to create this type is to use the following
* DQL statement:
CREATE TYPE "test_payment_check" (
account integer,
check_number integer,
transaction_date date,
amount float,
bank_code integer,
routing integer
) WITH SUPERTYPE "dm_document" PUBLISH
*
* This example also assumes that the repository name, username, and
* password are passed to the program on the command line.
*/
import com.documentum.com.DfClientX;
import com.documentum.com.IDfClientX;
import com.documentum.fc.common.*;
import com.documentum.fc.client.*;
IDfClientX clientx;
IDfClient client;
IDfSession session = null;
IDfSessionManager sMgr = null;
IDfBatchManager bMgr = null;
IDfLocalTransaction transaction;
int rpcCountAfter, rpcCountBefore;
try {
//create a Client object
clientx = new DfClientX();
client = clientx.getLocalClient();
25
Currency Scoping
bMgr.openBatch();
transaction = session.beginTransEx();
for ( int i = 0 ; i < 1 ; i++) {
createObject( session );
}
session.commitTransEx(transaction);
bMgr.closeBatch();
/* This section of code is identical the the previous one, except for the
* addition of transaction as the currency scope, so that the query in the
* method is only checked once during that scope.
*/
sMgr.getScopeManager().setDefaultScope(ScopeBoundary.TRANSACTION,
true);
rpcCountBefore =
session.getConnectionConfig().getInt("network_requests");
transaction = session.beginTransEx();
for ( int i=0 ; i < 100 ; i++) {
createObject( session );
}
session.commitTransEx(transaction);
rpcCountAfter =
session.getConnectionConfig().getInt("network_requests");
System.out.println(
"RPC calls with currency scoping boundary set to TRANSACTION: "
+ (rpcCountAfter-rpcCountBefore));
sMgr.getScopeManager().clearDefaultScope(ScopeBoundary.TRANSACTION);
rpcCountAfter =
session.getConnectionConfig().getInt("network_requests");
System.out.println(
26
Currency Scoping
/* This section of code is identical the the previous one, except for the
* addition of batch as the currency scope, so that the query in the
* method is only checked once during that scope.
*/
sMgr.getScopeManager().setDefaultScope(ScopeBoundary.BATCH, true);
rpcCountBefore =
session.getConnectionConfig().getInt("network_requests");
rpcCountAfter =
session.getConnectionConfig().getInt("network_requests");
System.out.println(
"RPC calls with currency scoping boundary set to BATCH: "
+ (rpcCountAfter-rpcCountBefore));
sMgr.getScopeManager().clearDefaultScope(ScopeBoundary.BATCH);
rpcCountBefore =
session.getConnectionConfig().getInt("network_requests");
rpcCountAfter =
session.getConnectionConfig().getInt("network_requests");
System.out.println("RPC calls with no currency scoping: "
+ (rpcCountAfter-rpcCountBefore));
/* This section of code is identical the the previous one, except for the
* addition of a custom currency scope, so that the query in the
* method is only checked once during that scope.
* Note that the call is to the Session Scope Manager in this section. A call
* to beginScope() by the Session Scope Manager begins the currency scope in the
* current session, but a call to beginScope() by the Scope Manager begins
* currency scoping in future sessions created by the Session Manager.
*/
rpcCountBefore =
session.getConnectionConfig().getInt("network_requests");
session.getSessionScopeManager().beginScope(true);
for ( int i=0 ; i < 100 ; i++) {
createObject( session );
}
session.getSessionScopeManager().endScope();
rpcCountAfter =
session.getConnectionConfig().getInt("network_requests");
System.out.println("RPC calls with a custom currency scoping: "
+ (rpcCountAfter-rpcCountBefore));
}
27
Currency Scoping
catch(Throwable e) {
if(e instanceof DfException) {
System.out.println("DFC Exception:");
String s = ((DfException)e).getStackTraceAsString();
System.out.println(s);
} else {
System.out.println("Non-DFC Exception");
e.printStackTrace();
}
}
finally {
if (session != null)
sMgr.release(session);
}
}
/* The section that follows queries for the object ID of the /System folder,
* and retrieves the object. Since this is unlikely to change during a session,
* there is a performance improvement if currency scoping is enabled.
* For this example code, currency scoping is enabled by the calling code,
* rather than here, demonstrating how the code behavior depends on the
* currency scoping set by the calling code.
*/
IDfQuery query = new DfQuery();
query.setCurrencyCheckValue(IDfSession.CURRENCY_CHECK_ONCE_PER_SCOPE);
query.setDQL("select r_object_id from dm_folder " +
"where any r_folder_path = '/System'");
IDfCollection collection =
query.execute(session, DfQuery.DF_CACHE_QUERY);
if (collection.next()) {
IDfId folderId = collection.getId("r_object_id");
folder = (IDfFolder) session.getObjectWithCaching( folderId, null,
null, IDfSession.CURRENCY_CHECK_ONCE_PER_SCOPE, false, false);
}
sysObj = (IDfSysObject)session.newObject("test_payment_check");
sysObj.save();
}
public static void main(String[] args)
throws java.lang.InterruptedException {
String docbase = args[0];
String user = args[1];
String password = args[2];
new StdScopingExample().begin(user, password, docbase);
}
}
28
Chapter 4
Data Partitioning
Data partitioning allows Documentum Server to use, and to be aware of, the partitioning features
of the underlying database to store object metadata in partitions in that database. Partitioning the
repository can allow optimized queries (if the partition is known) and storage of data on different
physical devices based on storage and access requirements. It also allows a technique to improve
loading of objects by first loading into a schema-equivalent offline table and then exchanging the
offline table into the repository.
Data partitioning is only supported on Oracle and SQL Server installations currently. Data
partitioning must be enabled on the underlying RDBMS for Documentum Server to use this feature.
Before Documentum Server supported partitioning, some installations used hash partitioning in
the underlying RDBMS to improve performance. The hash was based on the object ID, so typical
database access was spread across the partitions. A partitioning aware repository, in contrast, uses
range partitioning for the tables of partitioned types. A new internal integer column i_partition is
added to the tables of types that are partitionable. That i_partition column is used as the partition
key when the database tables are created. The value of i_partition will be exposed as an attribute
in the base type of objects, so Documentum Server can read and modify the partition where an
object's metadata is stored, can write queries to target specific partitions, and can group related
objects into the same partition.
Subtypes are partitionable if their supertypes are. If a supertype is partitioned, then all subtypes
created from it are also partitionable. If a supertype is not partitioned, a subtype cannot be partitioned
either.
Note: For release 6.5, Documentum Server used a different model of partitioning, did not use a
scheme object, and used a different administrative method to handle partitioning. Documentum
High-Volume Server 6.5 Development Guide provides information about the earlier model. Also, see
Upgrading from release 6.5, page 33, if you are upgrading a partitioned repository from release 6.5.
To use data partitioning, you must use the PARTITION_OPERATION administrative method
to create (or modify) the partitioning scheme object for your application. This object contains the
partition names, the associated i_partition ranges, and the tablespace (or filegroup) where the
database stores the tables. The object also has attributes that lists the types and registered tables
associated with the partition scheme. A type or registered table can only be in one partition scheme,
and cannot be moved to another scheme. You cannot directly modify any of the properties of a
dm_partition_scheme object, except for the object_name property. All other modifications are done
through the PARTITION_OPERATION method.
This method generates an SQL script to run against the database that creates the partitions and
specifies the ranges of i_partition values for objects that will reside in those partitions.
29
Data Partitioning
The following intrinsic types are partitioned in a newly-created repository if partitioning was selected
during creation:
• dm_acl
• dm_sysobject
• dmr_containment
• dm_assembly
• dm_relation
• dm_relation_type
• dmi_otherfile
• dmi_replica_record
• dmr_content
• dmi_subcontent
• dmi_queue_item
Use the PARTITION_OPERATION administrative method to create the partitioning scheme and to
generate the partitioning script needed to create the partitions.
30
Data Partitioning
31
Data Partitioning
32
Data Partitioning
IDfPersistentObject
It is the application’s responsibility to properly set the value for the i_partition attribute when a new
object is created for a partitionable type. It is also the application’s responsibility to ensure partition
alignment when creating unrelated objects, if they should be aligned. For example, if two objects
share content, they must be in the same partition.
To enable applications to set or retrieve the i_partition value, two new public APIs setPartition() and
getPartition() are added to IDfPersistentObject DFC interface. The methods are listed below:
• void setPartition(integer partition) throws DfException
Sets the i_partition value on the object
• int getPartition(integer partition) throws DfException
Retrieves the i_partition value from the object
If an application creates an object and does not specify its i_partition value, that value is automatically
set to 0, so the object will be assigned to the first partition. If an application assigns an i_partition
value greater than the largest currently defined partition range, the object will be assigned to the last
partition. In normal use, the last partition should not contain any objects.
IDfSession
The following method is similar to the public method getObject():
• IDfPersistentObject getObjectWithOptions(IDfID objectID, IDfGetObjectOptions objectOptions)
throws DfException
Use the objectOptions parameter to set the partition ID as a hint to fetch the object. With that hint,
Documentum Server will fetch the object more efficiently.
33
Data Partitioning
34
Data Partitioning
35
Data Partitioning
Then create the lightweight type with the following DQL command:
CREATE LIGHTWEIGHT TYPE test_payment_check (
account integer,
check_Number integer,
transaction_date date,
amount float,
deductions float repeating
) SHARES test_payment_bank PUBLISH
36
Data Partitioning
"tablespace"='dm_<repository name>_DOCBASE',
"partition_name"='<name of the second partition, for example P2>',
"range"=<specify the range, for example 200>,
"tablespace"='dm_<repository name>_DOCBASE',
"partition_name"='<name of the nth partition>',"range"=<specify the range>,
"tablespace"='DM_<repository name>_DOCBASE'
The result of this command is the object ID of the dm_partition_scheme object that you have
just created.
2. Now that the partition scheme is created, generate the SQL script to run against the database.
In this example, you run the db_partition operation without specifying any tables or types.
Run the following command in DQL:
EXECUTE partition_operation WITH "operation"='db_partition',
"partition_scheme"='<name of the scheme>'
If you created the repository with partitioning enabled, then you will add the additional partitions
needed for this example slightly differently. Since dm_sysobject and dmr_content are already
partitioned and have their own partition schemes, we need to modify both of those schemes for this
example. First, you will add partitions to dm_sysobject_sch and dmr_content_sch. Second, you will
add the non-partitioned dmi_object_type table to the dm_sysobject_sch. The first steps are done
37
Data Partitioning
online by Documentum Server, the second step requires you to manually run the script against the
database.
First, use the following DQL command to add partitions to the dm_sysobject_sch:
EXECUTE partition_operation WITH "operation"='add_partition',
"partition_scheme"='dm_sysobject_sch',
"partition_name"='P1',"range"=100,"tablespace"='dm_techpubsglobal_docbase',
"partition_name"='P2',"range"=200,"tablespace"='dm_techpubsglobal_docbase'
This command runs the partitioning script on the database for you, so you do not run it manually.
Now, use the following command to add the same partitions to the scheme for dmr_content:
EXECUTE partition_operation WITH "operation"='add_partition',
"partition_scheme"='dmr_content_sch',
"partition_name"='P1',"range"=100,"tablespace"='dm_techpubsglobal_docbase',
"partition_name"='P2',"range"=200,"tablespace"='dm_techpubsglobal_docbase'
Retrieve the partitioning script, stop the server, run the script on the database, and restart the server.
You should now have a partitioned repository. The types and table needed for this example are now
represented by two partition scheme objects, dm_sysobject_sch and dmr_content_sch.
38
Data Partitioning
The process is slightly different for a repository that was originally partition-enabled and for one that
you enabled after creation. The originally partition-enabled repository has two partition schemes
that you work with, dm_sysobject_sch and dmr_content_sch, and the originally non-partitioned
repository uses one scheme, example_sch.
Originally non-partition-enabled
To create the offline tables in an originally non-partition-enabled repository for our example, use the
following command with example_sch:
EXECUTE partition_operation WITH "operation"='switch_out',
"partition_scheme"='example_sch',
"temp_table_suffix"='x',"partition_name"='P2',"execute_now"=TRUE
Originally partition-enabled
To create the offline tables in an originally partition-enabled repository for our example use the
following command with dm_sysobject_sch:
EXECUTE partition_operation WITH "operation"='switch_out',
"partition_scheme"='dm_sysobject_sch',
"temp_table_suffix"='x',"partition_name"='P2',"execute_now"=TRUE
39
Data Partitioning
The two DMR_CONTENT tables, DMR_CONTENT_R and DMR_CONTENT_S, keep track of the
location of each content file, it's format, and links the content to an object.
40
Data Partitioning
41
Data Partitioning
The TEST_PAYMENT_CHECK tables contain the metadata for the lightweight SysObjects to be
ingested. The properties defined for the type are populated here, as well as some table values
intended for the system. The link from each lightweight SysObject to its sharing parent is set with
the I_SHARING_PARENT property value. Repeating properties require an index position value,
stored in the I_POSITION property. The index is a negative integer.
42
Data Partitioning
NEXT_ID_LIST
This apply method reserves a list of object IDs from the repository. Use this method to reserve the
object IDs for the objects you plan to ingest using partition exchange. Each ingested object requires a
unique object ID, and this method allows you to reserve a set of IDs. Once reserved, the IDs will not
be used by the repository, so you will not ingest an object ID in use by another object.
Since the IDs will not otherwise be used by the repository, you will want to carefully consider how
many to reserve for each call. Reserve enough to reduce the number of ID requests, but not so many
as to use up IDs if the process fails, or that there are leftover IDs when the objects are created. The
equivalent API command is:
apply,c,NULL,NEXT_ID_LIST,TAG,I,08,HOW_MANY,I,100
The following is a short Java code snippet demonstrating its use. Supply the session, object tag, and
number of IDs requested to this method, and it will return a list of object IDs with the proper ID tag:
private static IDfCollection myGetNewObjectIds(IDfSession session, String tag,
String number) throws Throwable
{
IDfList args = new DfList();
IDfList types = new DfList();
IDfList values = new DfList();
args.appendString("TAG");
types.appendString("I");
values.appendString(tag);
43
Data Partitioning
args.appendString("HOW_MANY");
types.appendString("I");
values.appendString(number);
The sample program in Chapter 9, Sample Program for Generating Metadata for Partition Exchange
demonstrates using this method to retrieve object IDs for the new objects.
where the userid parameter is the username/password for the owner of Documentum Server, log
is the log file for the command, and setting DIRECT=TRUE bypasses Oracle's transaction control,
greatly increasing the ingestion rate. The control file contains the detailed commands to load the
data. There are five sqlloader command lines and five control files. You will need to edit the loader
command files and replace Exchange/Exchange with the username/password of Documentum Server.
Note: If you experience difficulties with the following information, please consult the Oracle
documentation or Oracle support for assistance.
These are the five loading command files:
load_dmi_object.cmd contains the following sqlloader commands:
now
sqlldr userid=username/password control=dmiObjectType.ctl log=dmiObjectType.log
DIRECT=TRUE
now
44
Data Partitioning
now
sqlldr userid=username/password control=testPaymentCheckS.ctl log=testPaymentCheckS.log
DIRECT=TRUE
now
This last file can be used to launch all the other files:
LoadUp.cmd contains the following commands:
start load_dmi_object.cmd
start load_dmr_content_r.cmd
start load_dmr_content_s.cmd
start load_test_payment_check_r.cmd
start load_test_payment_check_s.cmd
45
Data Partitioning
When you have finished loading the data, it is a good time to verify that the load has gone correctly.
Review the log files and be sure that the number of rows loaded is what you expected.
46
Data Partitioning
Finally, here is a file that will run all three of the index creation files. Again, you must substitute the
username/password of your repository for Exchange/Exchange.
47
Data Partitioning
Originally non-partition-enabled
Use the following command to switch the data from the temporary tables into the partition:
EXECUTE partition_operation WITH "operation"='switch_in',
"partition_scheme"='example_sch',
"temp_table_suffix"='x',"partition_name"='P2',"execute_now"=TRUE
Originally partition-enabled
Use the following two commands to switch the from the temporary tables into the partition:
EXECUTE partition_operation WITH "operation"='switch_in',
"partition_scheme"='dm_sysobject_sch',
"temp_table_suffix"='x',"partition_name"='P2',"execute_now"=TRUE
48
Data Partitioning
49
Data Partitioning
50
Chapter 5
Lightweight SysObjects
51
Lightweight SysObjects
like a standard object. You can read and modify any of the values for attributes of the lightweight
type, just as you would for a normal SysObject. You can read (get) any of the attribute values that you
normally can that are part of the parent type or its supertypes. However, if you attempt to set the
values of attributes of the parent type (or the inherited attributes from its supertypes), a lightweight
object behaves differently from a normal object.
Since the attribute values of the shared parent are used by all the other lightweight object children,
you cannot change the parent's attributes without affecting all of the children. To prevent changing
the attributes of the shared parent, but to allow changing those attributes for a specific child, a copy
of the shared parent object is created for the private use of the child lightweight object. When a
lightweight object has a private parent object, we call this a materialized lightweight object. Now the
child lightweight object and its private parent behave just like a normal object.
You can explicitly materialize a lightweight object by using the DFC materialize method, or the
lightweight object can automatically materialize when you attempt to modify shared parent attributes.
When you create the lightweight type, you specify if automatic materialization is allowed. If you don't
allow automatic materialization, any operation that would cause materialization generates an error.
A LWSO that is materialized can be unmaterialized. After performing the operations that require
materialization, you can either reparent the LWSO to the original shared parent, or to another shared
parent.
A listing of methods and their effects is shown in the section, Applying SysObject APIs to lightweight
objects, page 60. Some common things to be aware of are:
• folders—the link/unlink API will cause materialization, since it affects the shared parent. Place the
shared parent in a folder before attaching any child LWSOs. Therefore, all the child LWSOs must
be in the same folder as their shared parent.
• content type—setting content type will also cause materialization. Set the content type on the
parent before attaching the child LWSOs. All the content for the children will be of the same type.
• lifecycle—participating in a lifecycle requires the LWSO to be materialized.
52
Lightweight SysObjects
the shared parent, so, in effect, the lightweight objects all have identical values for the attributes in the
shared parent. This situation can change if some operation needs to change a parent attribute for
one of (or a subset of) the lightweight objects. Since the parent is shared, the change in an attribute
would affect all the children. If the change should only affect one child, that child object needs to
have its own copy of the parent. When a lightweight object has its own private copy of a parent, we
say that the object is materialized. Documentum Server creates rows in the tables of the shared type
for the object, copying the values of the shared properties into those rows. The lightweight object
no longer shares the property values with the instance of the shared type, but with its own private
copy of that shared object.
For example, if you checkout a lightweight object, it is materialized. A copy of the original parent is
created with the same r_object_id value as the child and the lightweight object is updated to point
to the new parent. Since the private parent has the same r_object_id as the lightweight child, a
materialized lightweight object behaves like a standard object. As another example, if you delete a
non-materialized lightweight object, the shared parent is not deleted (whether or not there are any
remaining lightweight children). If you delete a materialized lightweight object, the lightweight child
and the private parent are deleted.
When, or if, a lightweight object instance is materialized is dependent on the object type definition.
You can define a lightweight type such that instances are materialized automatically when certain
operations occur, only on request, or never.
This type shares with customer_record and is defined for automatic materialization.
Instances of the order record type will share the values of instances of the customer record object
type. By default, the order record instances are unmaterialized.
The order record instances represented by objID_2 and objID_3 share the property values of
the customer record instance represented by objID_B. Similarly, the order record object instance
represented by objID_5 shares the property values of the customer record object instance represented
53
Lightweight SysObjects
by objID_Z. The i_sharing_type property for the parent, or shared, rows in customer_record are set
to reflect the fact that those rows are shared.
There are no order record-specific rows created in customer_record_s for the unmaterialized order
record objects.
Because the order record object type is defined for automatic materialization, certain operations on
an instance will materialize the instance. This does not create a new order record instance, but
instead creates a new row in the customer record table that is specific to the materialized order
record instance.
Materializing the order record instances created new rows in the customer_record_s table, one row for
each order record object, and additional rows in each supertype table in the type hierarchy. The object
ID of each customer record object representing a materialized order record object is set to the object ID
of the order record object it represents, to associate the row with the order record object. Additionally,
the i_sharing_type property of the previously shared customer record object is updated. In the order
record objects, the i_sharing_parent property is reset to the object ID of the order record object itself.
54
Lightweight SysObjects
After the shareable type exists, the attribute type_category in dm_type will have a value 0x00000002
to indicate that a type is a shareable type. A shareable type will have the following new attributes:
• i_sharing_type
—an ID attribute records the ID of the topmost lightweight type which the sharing lightweight
object is an instance of. This attribute will be a null ID before the shareable instance is shared
by any lightweight object. Once shared by the first lightweight object, the following sharing
lightweight objects need to be instances of the topmost lightweight type or its subtypes.
• i_orig_parent
—an ID attribute records the original parent ID of a materialized lightweight object. This attribute
will record the ID of the shareable instance when the instance is first shared by any lightweight
object and remain the same afterwards even after the lightweight object is materialized and the
shareable instance is cloned for the materialized lightweight object.
• allow_propagating_changes
—a Boolean flag indicating whether any changes applied to the shareable instance which has the
consequence of propagating the changes to all its children are allowed. By default, this flag is
set to false.
The following are the changes that need to be propagated:
• Changes to any fulltext-indexable attributes.
• Changes to any retention-related attributes. That is, adding new values to the i_retainer_id or
dropping existing values from the i_retainer_id.
Any shareable object is not allowed to be versioned or deleted if it is shared by at least one lightweight
object. A shareable type is not allowed to become a non-shareable one. A shareable type can only be
dm_sysobject or any of its subtypes, but dm_sysobject is not shareable by default, but must be altered.
55
Lightweight SysObjects
FULLTEXT SUPPORT |
FULLTEXT SUPPORT LITE | BASE [ADD attribute_list | ALL]
]
[PUBLISH]
If no optional clauses are specified, the default is AUTO MATERIALIZATION and FULLTEXT
SUPPORT NONE. The LIGHTWEIGHT TYPE clause tells server that the new type is a lightweight
type and the SHARES clause tells server from what shareable type (and its subtypes) the instances
of the new type are sharing. That is, it defines the legal type of objects that can appear in the
i_sharing_parent attribute of the type.
A lightweight type can define any of its own attributes as non-qualifiable. If a lightweight type has
any non-qualifiable attribute, then it will have its own property bag columns defined on its own base
tables. However, the interface will make sure that all property bags of a lightweight object appear as
one property bag for the object.
The super type of a lightweight type recorded in dm_type is its parent type. The type_category
attribute of dm_type for a lightweight type is set to 0x00000004. A new attribute, shared_parent_name,
is added to dm_type to store the name of the shared parent type. This new attribute will help to
quickly identify the shared parent type for the subtypes of a lightweight type.
Note that the custom attributes, if any, can not overlap with parent type except the following
attributes:
• Subject
• Title
Otherwise, an error will be reported.
You can further subtype the lightweight type using the existing WITH SUPERTYPE clause. The
new subtype will have the same type hierarchy as usual. However, you can’t mix up the SHARES
clause with the WITH SUPERTYPE clause in the same CREATE TYPE or CREATE LIGHTWEIGHT
TYPE statement.
After the lightweight type exists, the attribute type_category in dm_type will have a value 0x00000004
to indicate that a type is a lightweight type. In addition to the custom attributes, the lightweight
type will have the following attributes:
• r_object_id
—an ID attribute.
• i_vstamp
—an integer attribute recording the version stamp of the object. This attribute serves as the
mechanism for concurrency control.
• i_partition
—an integer indicating the partition where the object resides. This attribute will exist only
when the lightweight type is declared for partitioning. A lightweight object will reside on the
same partition as its parent object.
• i_sharing_parent
—an ID attribute. This attribute points to the shared parent for the lightweight object. The object
will inherit all attributes and policies (i.e., ownership, security, retention, aspect, and so on) from
the shared parent. This attribute must point to a valid ID to share the properties from the parent.
A parent object is not allowed to be destroyed if there are lightweight objects pointing to it. When
a lightweight object is materialized, this attribute will store the same ID as the object itself.
56
Lightweight SysObjects
• object_name
—a CHAR(255) attribute
• r_page_cnt
—an integer indicating the number of content files associated with the lightweight object.
LITE keyword
Add the keyword LITE (similar to the keyword ALL), after the lightweight type name (or any of its
subtypes) to only query against the lightweight type without the parent type. For example, if you
issue the following DQL statement:
SELECT attrs_in_both_types
FROM dm_image_ingestion
WHERE predicates_involve_attrs_in_both_types
where dm_image_ingestion is the lightweight type that has dm_sysobject as its shareable parent type,
then the query will search the base tables of both dm_image_ingestion and dm_sysobject. However,
the following DQL statement will only query against dm_image_ingestion:
The following statement will only query against attributes defined in the lightweight type
SELECT only_attrs_in_the_lightweight_type
FROM a_lightweight_type (LITE)
WHERE predicates_involve_only_attrs_in_the_lightweight_type
You can still issue other DQL statements against any lightweight type just like a regular type. This
includes the FTDQL hint among others. The LITE keyword can only be used by the superuser.
57
Lightweight SysObjects
The results of a query that uses the HIDE_SHARED_PARENT DQL hint will not contain any shared
parents. A side effect of this hint is that queries will show shared parents without child objects, but
the shared parents will disappear from the results when a child LWSO is attached. Webtop uses this
hint by default.
This hint does affect performance, since there are the additional checks required to determine
whether the result contains shared parents.
58
Lightweight SysObjects
Operations that modify the attributes of the shared parent cause the lightweight object to materialize
(if allowed).
A materialized lightweight object behaves like a standard object, in that you can read and modify the
attributes of the lightweight and parent object just as with a normal SysObject.
IDfLightObject
The IDfLightObject interface provides methods to manipulate lightweight SysObjects.
• void dematerialize()
Turns a materialized lightweight SysObject back into an unmaterialized lightweight SysObject
by reparenting to the original shared parent.
• IDfId getSharingParent()
Returns the ID of the lightweight SysObject's parent.
• boolean isMaterialized()
Indicates whether the lightweight SysObject is materialized.
• void materialize()
Explicitly triggers the object to be materialized. A private parent copy of the shared parent is
created, and the object is reparented to the private parent.
• void reparent(IDfId newParentId)
The lightweight SysObject is set to point to the new shareable parent object. Use this method to
reparent one child object. Use the method IDfSession.reparentLightObjects() to reparent a list
of lightweight SysObjects.
IDfSession
Methods have been added to IDfSession to create and reparent lightweight SysObjects.
• IDfPersistentObject newLightObject(String typeName, IDfId parentId)
Use this method to create a new lightweight SysObject. The typeName must be an existing
lightweight type, and the parentId must be an existing object of the shareable type shared by
the lightweight type.
• void reparentLightObjects(IDfId newParentId, IDfList childIds)
The method reparents a list of lightweight SysObjects to a new parent. The newParentId must
be an existing object of the shareable type shared by the lightweight objects. The childIds must
all be of the lightweight type that shares the newParentId type. To reparent a single lightweight
object, use the IDfLightObject.reparent() method.
59
Lightweight SysObjects
Almost all the getters like getAcl (except the getObjectName and getPageCount, and the getTitle
and getSubject, which return the respective values of the object_name and page count from the
lightweight object) and the status checking APIs (like isFrozen) will directly return the corresponding
attribute values from the parent object.
60
Lightweight SysObjects
If an API is applied to an attribute which has the same name as the parent, then it will be applied to
the lightweight object. APIs like getPageCount, getObjectName and setObjectName (and perhaps
getTitle and getSubject) are in this category. For the lock API, it makes sense to perform the operation
on the lightweight object. All the content-related getter and setter APIs will be applied to the
lightweight object, accordingly.
The following APIs will cause the lightweight object to be materialized so that existing applications
will work properly:
• All the non-content related setters
• If the lightweight object doesn’t have any content, then content attribute related APIs like
setStorageType and setContentType will cause the lightweight object to be materialized.
Otherwise, the setStorageType will cause the contents to be migrated to the new storage area after
the materialization and the setContentType will be disallowed.
• The link/unlink API. This implies that all of the lightweight child objects must be in the same
folder as their shared parent. You can link the shared parent object to a folder before adding
lightweight children.
• The checkout/checkin API. Note that both lightweight objects and the cloned parent will have new
versions.
• Saveasnew. If saveasnew is applied to a non-materialized lightweight object, then only the
lightweight object will be cloned as a new object pointing to the same parent. If it is applied to a
materialized lightweight object, then both the lightweight object and its parent will be cloned as
another new materialized lightweight object.
• Branch. If branch is applied to a non-materialized lightweight object, it is disallowed. If it is
applied to a materialized lightweight object, then both the lightweight object and its parent will be
cloned as a branched version of the original one.
• Set retention
• Set VDM children and assemble APIs
61
Lightweight SysObjects
If the parent object is registered for auditing or event notification, then changes to the lightweight
object will be audited or notified accordingly. Setting the policy-related attributes (for example:
security, retention, owner, lifecycle, and others) on the parent object will affect the lightweight
object as well. Changing the parent’s a_storage_type will only affect new contents created for the
lightweight objects, not for existing contents.
Once a lightweight object is materialized, you can use it in any place where a SysObject is allowed.
However, if the lightweight object hasn’t been materialized, then the application needs to be enhanced
so that it knows how to deal with the lightweight object. For example, you will be able to place the
lightweight object in a dm_relation object as the parent or the child. However, the application using
the relationship needs to know how to deal with the special type in the relationship.
62
Lightweight SysObjects
63
Lightweight SysObjects
loginInfoObj.setPassword(password);
// Bind the Session Manager to the login info
sMgr.setIdentity(docbaseName, loginInfoObj);
session = sMgr.getSession(docbaseName);
// Create Parent
sysObj = (IDfSysObject)session.newObject("test_payment_bank");
sysObj.setObjectName("check_parent");
// Storage type MUST be set on the parent, otherwise the
// lightweight object will be materalized.
// An alternative is to use the DQL statement:
// ALTER TYPE test_payment SET DEFAULT STORAGE 'filestore_01'
sysObj.setStorageType("filestore_01");
// Content type MUST be set on parent, otherwise the
// lightweight object will be materalized.
sysObj.setContentType("gif");
// Set shared attributes
sysObj.setInt("bank_code", 1);
sysObj.setInt("routing", 231381116);
sysObj.save();
objId = sysObj.getObjectId();
for (int i=0; i<10; i++) {
// Create 10 childern
IDfTime currDate = new DfTime();
sysObj = (IDfSysObject)session.newLightObject(
"test_payment_check",objId);
sysObj.setObjectName("check_" + i);
sysObj.setFile("check.gif");
// Set individual attributes
sysObj.setInt("check_number",i);
sysObj.setTime("transaction_date", currDate);
sysObj.setInt("account", 1000000);
sysObj.setDouble("amount", 25.00);
sysObj.save();
}} catch(Throwable e) {
if(e instanceof DfException) {
System.out.println("DFC Exception:");
String s = ((DfException)e).getStackTraceAsString();
System.out.println(s);}
else {
System.out.println("Non DFC Exception");
e.printStackTrace();
}} finally {
if (session != null)
sMgr.release(session);
}}
public static void main(String[] args)
throws java.lang.InterruptedException {
String docbase = args[0];
String user = args[1];
String password = args[2];
new lwsoExample().begin(user, password, docbase);
}
}
64
Chapter 6
PARTITION_OPERATION Method
The following information is from the Documentum Server DQL Reference Guide, describing the
PARTITION_OPERATION administration method.
PARTITION_OPERATION
Creates partitioning scheme objects and SQL scripts to control repository partitioning.
• db_partition
• add_partition
• delete_partition
• split_partition
• merge_partition
• switch_out
• switch_in
partition_scheme string scheme_name
partition_name string partition_name The name of the partition. Some
databases may restrict the choices
for a partition name. For example,
choosing default as a partition
name causes an error when you
execute the partitioning script.
65
PARTITION_OPERATION Method
Syntax
To create a partitioning scheme object:
EXECUTE partition_operation WITH operation='create_scheme',partition
_scheme='scheme_name'{,partition_name='partition_name',range=right
_limit,tablespace='storage_name'}
To add a partition (range must be greater than the upper bound of the scheme):
66
PARTITION_OPERATION Method
To merge a partition with the one to its left (with a lower range):
EXECUTE partition_operation WITH operation='merge_partition',partition_scheme
='partition_scheme',partition_name='partition_name'
Arguments
Table 7. PARTITION_OPERATION arguments
• db_partition
• add_partition
• delete_partition
• split_partition
• merge_partition
• switch_out
• switch_in
partition_scheme string scheme_name
67
PARTITION_OPERATION Method
Return value
For create_scheme, PARTITION_OPERATION returns a Boolean value and an object id. The Boolean
value indicates if the operation succeeded. The object ID is either the ID of the partition scheme object,
or the object ID of the SQL script that is run against the database to perform the partitioning operation.
68
PARTITION_OPERATION Method
Note: One way to retrieve the script is to issue the following DQL statement (assume that the result of
PARTITION_OPERATION returned the object ID 0855706080007c19):
EXECUTE get_file_url FOR '0855706080007c19' WITH "format"='text'
That statement will return the location of the file.
Permissions
You must have Sysadmin or Superuser privileges to use all the operations of this method. If you have
type owner privileges, you can use the db_partition operation for that type.
In Oracle installations, you must be logged in as sysdba to run the script.
Descriptions
Use this method to create a partitioning scheme object (dm_partition_scheme). This object will record
the types and tables that use the scheme, the name and range of each partition, and the tablespace
(or filegroup) where each partition is stored. When a partitioning scheme object is first created,
there are no types or registered tables associated with it, just the name, range and tablespace for the
partitions in the scheme. When you associate types or registered tables with a partitioning scheme, a
script is created that must be run against the underlying database to partition the database tables
to match the partitioning scheme. Documentum Server does not run this script since it may take a
long time to perform the partitioning on a large database, and you may want to examine the script
before running it.
You also use this method to modify a partition scheme. Modifying the scheme also creates a database
partitioning script that Documentum Server runs against the database for you.
When you run the script-creating variations of this method, the method returns the r_object_id of the
partitioning script to run in your database. The partition scheme object information and the database
are not consistent until the script is run, so the is_validated property of the partitioning scheme object
is set to FALSE. After the script is created, you must run it against the underlying database, using the
database's SQL facility. The scripts make the changes to the database that reflect the information in
the partition scheme object. As the script is successfully run against the database, the is_validated
property of the partitioning scheme object is set to TRUE.
If you did not enable partitioning when you created your repository, create a scheme, and then
use the db_partition operation without specifying any tables or types to partition the repository
intrinsic types.
The following are the intrinsic type hierarchies that are partitioned when you create a repository with
partitioning enabled, or you later enable partitioning:
• dm_acl
• dm_sysobject
• dmr_containment
• dm_assembly
• dm_relation
69
PARTITION_OPERATION Method
• dm_relation_type
• dmi_otherfile
• dmi_replica_record
• dmr_content
• dmi_subcontent
• dmi_queue_item
Create_scheme
To create a partition scheme, use the create_scheme operation. You will specify a name for the
scheme. Each scheme has a unique name. In this document we use the convention that the name
of a partition scheme ends with the characters _sch. In addition to the scheme, you will specify
one or more partition name, range, and tablespace. The name is used to refer to the partition. The
range is a single integer that is one larger than the largest value in the i_partition attribute for any
objects in that partition. The tablespace specifies where the partition is stored. The r_object_id of the
partition scheme object is returned.
The following command creates a partition scheme named my_partition_sch, with four partitions
named zero, first, second, and third. Partition zero contains objects with i_partition values from 0 to
9, partition first contains objects with i_partition values from 10 to 19, partition second has 20 to 29,
and partition third has 30 to 39. Notice that the range for partition zero is set to 10, but partition zero
contains objects with i_partition values from 0 to 9:
70
PARTITION_OPERATION Method
Db_partition
To apply a partition scheme, use the db_partition operation. You specify the partition scheme to
apply, and the types and tables to partition. This operation adds the specified types and registered
tables to the partition scheme object, and creates a script that partitions the database tables. A type
or registered table can be associated with only one partition scheme, so the command will fail if a
type or registered table is listed in any other partition scheme.
Use this operation to partition-enable a repository that was not originally created as partition-enabled.
If you run this operation and do not specify any types or registered tables, the base types will be
partitioned. Also, see the note below about increasing the number of cursors for an Oracle installation.
After you have created a partition scheme, perform these steps to partition the repository:
1. Use the db_partition operation of the PARTITION_OPERATION administrative method to
create the partitioning script
2. Stop Documentum Server
3. Execute the partitioning script against the database
4. Restart Documentum Server
Note: Do not execute the script if there have been changes to the repository schema after it was
generated. Create a new script if the schema changes.
The following command creates a script to apply my_partition_sch to the type, my_type. The
command returns the r_object_id of the script, and sets the is_validated property of my_partition_sch
to FALSE:
EXECUTE partition_operation with "operation"='db_partition',
"partition_scheme"='my_partition_sch',"type_name"='my_type'
After running the script, the is_validated property is TRUE, and the tables in the underlying database
are partitioned as set out in the my_partition_sch object.
Add_partition
To add a partition, use the add_partition operation. You specify the partition name, range, and
tablespace for each partition to add. The range of the new partition must be greater than the upper
bound of the current partition scheme. Any types or registered tables already attached to this
partition scheme will be modified. This operation modifies the partition information in the partition
scheme object, and creates and runs a script to modify the partitioning in the database.
71
PARTITION_OPERATION Method
The following command adds a partition to the partition scheme my_partition_sch, and runs a script
to add the additional partition to the database tables. In this example assume that my_type was
partitioned in the earlier db_partition example:
EXECUTE partition_operation WITH "operation"='add_partition',
"partition_scheme"='my_partition_sch'
,"partition_name"='fourth',range=50,"tablespace"='dm_techpubsglobal_docbase'
Delete_partition
To delete a partition, use the delete_partition operation. The partition must be the last partition in
the partition scheme. Like add_partition, this operation modifies the partition information in the
partition scheme object, and runs a script to modify the partitioning in the database.
The following command removes the last partition (created in the add_partition example):
EXECUTE partition_operation WITH "operation"='delete_partition',
"partition_scheme"='my_partition_sch',"partition_name"='fourth'
Split_partition
To split a partition, use the split_partition operation. You specify a source partition to split, and the
name, range, and tablespace of the new partition. The range value must fall into the defined range
of the source partition. The new partition is to the left of the source partition (the new partition
range is lower than the modified source partition).
The following command splits the zero partition into partitions five and zero:
EXECUTE partition_operation WITH "operation"='split_partition',
"partition_scheme"='my_partition_sch',
"source_name"='zero',
"partition_name"='five',range=5,"tablespace"='dm_techpubsglobal_docbase'
If you used the previous examples, before executing this command, the partition names and ranges
are: zero (10), first (20), second (30), third (40). After executing this command, they are: five (5), zero
(10), first (20), second (30), third (40).
Merge_partition
To merge two partitions, use the merge_partition operation. This operation merges the partition
specified into the partition on its left (into the lower range numbered partition).
The following command merges the partition named five into the next lower range partition
(partition zero, if you've used the previous examples):
EXECUTE partition_operation WITH "operation"='merge_partition',
"partition_scheme"='my_partition_sch',"partition_name"='five'
72
PARTITION_OPERATION Method
Switch_out
To move data out of a partition into temporary tables, use the switch_out operation. For some
databases (SQL Server), the temporary tables (if they've already been created), must be empty. After
the switch_out operation, the temporary table contents will be in the partition, and the data previously
in the partition will reside in the temporary tables for the types and registered tables in that partition
scheme. If you specify execute_now as TRUE, Documentum Server will execute the SQL script and
switch out the data, otherwise you will need to run the script yourself. The temporary table names
will match the type or registered table name that you switch out with the temp_table_suffix added.
While switch_out is executing, the data in the partition is not consistent, so you must insure that there
is no repository access to that partition during the switch.
The following example switches out the data in the second partition into a temporary table named
my_type_x (my_partition_sch only has one type, my_type, in it). Since execute_now is specified, you
do not need to run the SQL script; it is done for you:
EXECUTE partition_operation WITH "operation"='switch_out',
"partition_scheme"='my_partition_sch',
"temp_table_suffix"='_x',"partition_name"='second',"execute_now"=TRUE
Switch_in
To move data into a partition from temporary tables, use the switch_in operation. The partition must
be empty for SQL Server. Create the temporary tables and fill them with the data to switch into the
partition. After the switch_in operation, the temporary table contents will be in the partition, and
the data previously in the partition will reside in the temporary tables. If you specify execute_now
as TRUE, Documentum Server will execute the SQL script and switch out the data, otherwise you
will need to run the script yourself. The temporary table names will match the type or registered
table name that you switch out with the temp_table_suffix added.
You must have created all the temporary tables to switch into the empty partition. One quick way to
create those tables, is to use the switch_out operation on an empty partition. When the operation
executes, it will create all the required tables. Since the partition was empty, all the tables will be, too.
You can then fill the tables with data.
While switch_in is executing, the data in the partition is not consistent, so you must insure that there
is no repository access to that partition during the switch.
The following example switches in the data in the from the temporary table named my_type_x
(my_partition_sch only has one type, my_type, in it) into the partition named second. Since
execute_now is specified, you do not need to run the SQL script; it is done for you:
EXECUTE partition_operation WITH "operation"='switch_in',
"partition_scheme"='my_partition_sch',
"temp_table_suffix"='_x',"partition_name"='second',"execute_now"=TRUE
Oracle installations
Note: If you experience difficulties with the following information, please consult the Oracle
documentation or Oracle support for assistance.
73
PARTITION_OPERATION Method
In order to use this method with an Oracle installation, you must run the script as SYSDBA.
Additionally, if you are partitioning a non-partitioned database, you may want to increase the number
of open database cursors, or the script may exit with the error:
ORA-0100 Max Opened Cursors Exceeded
To increase the number of cursors, consult your Oracle documentation. It may tell you to use a
command similar to:
ALTER SYSTEM SET OPEN_CURSORS=2000 SCOPE=MEMORY SID='*';
For example, if dmadmin is the installation owner:
C:\Documents and Settings\dmadmin>sqlplus "/as sysdba"
@ C:\Documentum\data\testenv\content_storage_01\00000057\80\00\01\19.txt
Additionally, if you are partitioning a non-partitioned database, you may want to increase the number
of open database cursors, or the script may exit with the error:
ORA-0100 Max Opened Cursors Exceeded
74
PARTITION_OPERATION Method
The typical steps you would take to do a partition exchange involve the following:
1. Create the offline tables.
2. Load the offline tables.
Load the tables with data using whatever methods are available to you with your database.
3. Create the offline index tables.
The offline tables must index the same properties as the online objects do. The schema must be
identical. Create the offline index tables in the same tablespace as the current online indexes.
4. Exchange the partition for the offline tables.
Run the PARTITION_OPERATION administration method to switch in or switch out the data.
After following these steps, the data that was previously in the offline tables is in the online
partition, and the previously online data is now in the offline table.
5. Validate the exchange.
Check the online data to be sure that the exchange was successful.
75
PARTITION_OPERATION Method
76
Chapter 7
GENERATE_PARTITION_SCHEME
_SQL Method
The following information is from the Documentum Server DQL Reference Guide, describing the
GENERATE_PARTITION_SCHEME_SQL administration method. This method is deprecated.
GENERATE_PARTITION_SCHEME_SQL —
Deprecated
(Starting from the 6.6 release, this method is deprecated. See PARTITION_OPERATION, page 65, for
its replacement.) Creates an SQL script to control repository partitioning.
Syntax
To generate a script to partition a database:
EXECUTE generate_partition_scheme_sql WITH [operation='db_partition',]
[type_name='type_name',|table_name='regtable_name',[owner_name='owner_name',]]
[last_partition ='partition_name',last_tablespace='tablespace',]
partition_name='partition_name',range=integer,tablespace='tablespace'
{,partition_name='partition_name',range=integer,tablespace='tablespace'}
[,include_object_type={TRUE|FALSE}]
77
GENERATE_PARTITION_SCHEME_SQL Method
partition_name='partition_name'
,include_object_type={TRUE|FALSE}
Arguments
Table 8. GENERATE_PARTITION_SCHEME_SQL arguments
78
GENERATE_PARTITION_SCHEME_SQL Method
Return Value
GENERATE_PARTITION_SCHEME_SQL returns an object id for the text file containing the SQL
script to generate the partitioning.
Permissions
You must have Sysadmin or Superuser privileges to use this method.
In Oracle installations, you must be logged in as sysdba to run the script.
Description
Note: Starting from the 6.6 release, this method is deprecated and is replaced by
PARTITION_OPERATION.
Use this method to generate a database partitioning script. After the script is generated, it is run
against the underlying database, using the database's SQL facility. For all versions of this method,
except for add_partition, stop Documentum Server before you run the script against the database,
then restart Documentum Server for the changes to take effect. For the add_partition method, you do
not need to stop or restart Documentum Server.
The first form of the command, in which operation='db_partition', allows you to specify a type or
a table to partition. If you do not specify a type or table, the generated script will partition all the
partitionable types in the repository if it is run. You would use this command to partition a repository
that was upgraded from an earlier version. The first range value means that objects with i_partition
values from 0 to the first value will be in the first partition. The second partition will contain objects
with i_partition values greater than first range value up to the second range value. Each subsequent
partition will contain all the objects with i_partition values greater than the previous partition and
up to its value. The last partition contains those objects with i_partition values greater than any
previously specified partition.
The second form of the command, in which operation='add_partition', allows you to add partitions.
This form is similar to the first form, but the first added partition begins with values greater than
previously defined partitions. If there happen to be objects in the last partition whose i_partition
values fall into the new partition's range, they will be moved into the new partition.
If you create a new repository with partitioning enabled, there is only one partition, called the last
partition. You can then customize your repository by adding partitions. In this case, the first added
partition range goes from 0 to the value you specified.
The final two versions, in which operation='exchange_partition', allow you to exchange a partition
with a schema-identical offline table in the database tablespace. Commonly, you would use this
feature to load a large number of objects into a table and then swap the table into the partition.
79
GENERATE_PARTITION_SCHEME_SQL Method
Oracle installations
In order to use this method with an Oracle installation, you must run the script as SYSDBA. For
example, if dmadmin is the installation owner:
C:\Documents and Settings\dmadmin>sqlplus "/as sysdba"
@ C:\Documentum\data\testenv\content_storage_01\00000057\80\00\01\19.txt
Additionally, if you are partitioning a non-partitioned database, you may want to increase the number
of open database cursors, or the script may exit with the error:
ORA-0100 Max Opened Cursors Exceeded
To increase the number of cursors, consult your Oracle documentation. It may tell you to use a
command similar to:
ALTER SYSTEM SET OPEN_CURSORS=2000 SID='*' SCOPE=MEMORY;
or for Oracle versions earlier than Oracle 11:
ALTER SYSTEM SET OPEN_CURSORS=2000 SCOPE=MEMORY SID='*';
to alter the number of open cursors.
If you exit the script with an error (from inadvertently exceeding the number of open cursors, for
example), correct the error, and rerun the script, you may see an error message like:
ORA-12091: cannot online redefine table "TECHPUBS"."DMC_WFSD_ELEMENT_S" with
materialized views
caused by leftover temporary items from the previous script failure. One way to correct this error is
to run a command similar to:
execute DBMS_REDEFINITION.ABORT_REDEF_TABLE('<Schema Name>', '<Table Name>'
,'<Table Name>I');
Where <Table Name>I is the intermediate table name used for the redefinition. From the previous
error message, we would use this command:
execute DBMS_REDEFINITION.ABORT_REDEF_TABLE('TECHPUBS', 'DMC_WFSD_ELEMENT_S'
,'DMC_WFSD_ELEMENT_SI');
and
last_tablespace='filegroup'
for SQL Server installations.
80
GENERATE_PARTITION_SCHEME_SQL Method
Partition Exchange
Partition exchange must be carefully planned. Typically, you will create a number of offline tables to
load with data, use whatever native database method is available to load the tables, create the table
indexes, and then swap the tables into the prepared repository partition. This technique can load
large amounts of data into a repository while causing a minimum of disruption to normal use of the
repository. This technique can also be used to remove large amounts of data from a repository by
swapping out a partition for small offline tables.
The typical steps you would take to do a partition exchange involve the following:
1. Identify the offline tables to create.
2. Load the offline tables.
Load the tables with data using whatever methods are available to you with your database.
3. Create the offline index tables.
The offline tables must index the same properties as the online objects do. The schema must be
identical. Create the offline index tables in the same tablespace as the current online indexes.
4. Exchange the partition for the offline tables.
Run the GENERATE_PARTITION_SCHEME_SQL administration method to generate the
partitioning script, stop Documentum Server, run the script against the RDBMS, and restart
Documentum Server. After following these steps, the data that was previously in the offline
tables is in the online partition, and the previously online data is now in the offline table.
5. Validate the exchange.
Check the online data to be sure that the exchange was successful.
Documentum Server Administration and Configuration Guide contains more information about executing
a partition swap.
Examples
This example generates a script to partition all the partitionable types in a repository. After the script
is run, partitionable objects with an i_partition value of 0 to 10 will be stored in partition P1 of the
database. Partitionable objects with an i_partition value of 11 to 20 will be stored in partition P2
of the database.
EXECUTE generate_partition_scheme_sql WITH
"partition_name"='P1',"range"=10,"tablespace"='dm_techpubs_docbase',
"partition_name"='P2',"range"=20,
"tablespace"='dm_techpubs_docbase'
81
GENERATE_PARTITION_SCHEME_SQL Method
To get the script, you can issue the following DQL statement (assume that the result of the
earlier method returned the object ID 0855706080007c19): EXECUTE get_file_url FOR
'0855706080007c19' WITH "format"='text'
82
Chapter 8
MIGRATE_TO_LITE Method
The following information is from the Documentum Server DQL Reference Guide, describing the
MIGRATE_TO_LITE administration method.
MIGRATE_TO_LITE
Migrates standard objects to lightweight objects.
Syntax
To generate, and optionally run, a script to split standard objects into a shareable parent object and
a lightweight object:
EXECUTE migrate_to_lite WITH source_type='source_type'
,shared_parent_type='shared_parent_type'
,execution_mode='execution_mode_split'[,recovery_mode=TRUE|FALSE]
,parent_attributes='parent_properties'
[ft_lite_add='property_list' | ft_base_add='property_list']
To generate, and optionally run, a script to migrate standard objects to lightweight objects:
EXECUTE migrate_to_lite WITH
shared_parent_type='shared_parent_type'
[,lightweight_type='lightweight_type']
,execution_mode='execution_mode'[,recovery_mode=TRUE|FALSE]
{,parent_sql_predicate='parent_sql_predicate'}
{,parent_id='ID'}
[,default_parent_id='ID']
[ft_lite_add='property_list' | ft_base_add='property_list']
83
MIGRATE_TO_LITE Method
Arguments
Table 9. MIGRATE_TO_LITE arguments
• Finalize
84
MIGRATE_TO_LITE Method
• Cancel
• Finalize
85
MIGRATE_TO_LITE Method
86
MIGRATE_TO_LITE Method
Return Value
MIGRATE_TO_LITE returns an object id for the text file containing the SQL script to do the migration.
The script will be generated regardless of the execution_mode specified.
87
MIGRATE_TO_LITE Method
When you use this command to split a type, the indexes on the type attributes are dropped. You will
need to evaluate which attributes to index, and create those indexes, after splitting the type into
a lightweight and a shareable type.
Permissions
You must have Superuser privileges, or be the owner of the involved types, to use this method. But
also see the note for Oracle installation users following the description section.
Description
Use this method to migrate standard types and objects to shareable and lightweight types and objects.
This method can also be used to reparent lightweight objects.
The first form of the command is used to convert a standard type to a lightweight and a shareable
type. In this form of the command, the shareable type is formed by splitting off properties from the
original standard type. The remaining properties are used to create the lightweight type. Specify
the name of the standard type to split in the source_type parameter, the new shareable type in
the shared_parent_type parameter, and list the properties to split off of the original type in the
parent_attributes parameter. When you use this method to split standard objects, each lightweight
object has its own private parent. In other words, each lightweight object is materialized. You
can then reparent the lightweight objects by using the second form of the command, specifying
parent_sql_predicates and parent_ids to point the lightweight objects to shareable parents.
The second form of the command does not move properties from one type to another. You will use it
when all the non-inherited standard type properties will remain with the lightweight type. You can
also use this form to reparent lightweight objects.
88
MIGRATE_TO_LITE Method
If you use the second form of the command and do not specify a lightweight type, and you specify a
standard type in the shared_parent_type argument, the standard type is changed into a shareable
type.
The second form can convert standard objects to lightweight objects and parent them with specified
shareable parents. To do this, you specify a shared_parent_type and a lightweight_type. Conceptually,
you can imagine that all the standard objects specified by the lightweight_type argument are
converted to materialized lightweight objects pointing to private parents of the shared_parent_type.
Next, all the objects of the lightweight type that match the parent_sql_predicate argument are made
to point to the shareable parent with the associated parent_id. The method continues associating
each group of lightweight objects that matches each subsequent parent_sql_predicate and parenting
that group with the associated shareable parent. If any unconverted materialized lightweight objects
remain after converting each parent_sql_predicate group, the remaining objects are parented with
the default_parent_id shareable parent, if specified. Typically, you would create some shareable
parents ahead of time, and then use this method to associate that list of objects with the groups
defined by the parent_sql_predicate.
To use this method to reparent lightweight objects, specify the shared_parent_type and the
lightweight_type, the parent_sql_predicate to select which objects to reparent and the parent_id to
reparent to. You must also specify recovery_mode as TRUE, or the method won't work with already
converted objects of lightweight_type.
Fulltext Support
Use the ft_lite_add and ft_base_add arguments to specify which properties are included in the fulltext
index. These arguments add the shareable parent type properties and the lightweight type properties
to fulltext indexing. The ft_lite_add variations add the properties specified for the lightweight type,
and the ft_base_add variations add the properties specified for the shareable parent type.
Note: In order to use this method with an Oracle installation, the user account that Documentum
Server uses to access the database must have enhanced privileges. The following example assumes
that you have logged into SQLPLUS as the SYS user, in SYSDBA mode to grant these privileges to
the repository_1 user:
grant DBA to repository_1;
These are powerful privileges and should be revoked when the migration is completed.
Examples
This example generates a script to convert usertype_1 to a shareable type. You do not execute this
script against your database. It is created so you can examine the commands that will be issued
when you later execute this method using another form of the method, either Run and Finalize or
Run without Finalize:
EXECUTE migrate_to_lite WITH "shared_parent_type"='usertype_1'
,"execution_mode"='Generate Script Only'
89
MIGRATE_TO_LITE Method
To get the script, you can issue the following DQL statement (assume that the result of the earlier
method returned the object ID 0855706080007c19):
EXECUTE get_file_url FOR '0855706080007c19' WITH "format"='text'
This example converts usertype_3 to a shareable type in two steps. After step one, you can examine
the script and the temporary types and tables to verify the repository changes. For step one, use the
Run without Finalize execution_mode to run the script and create the temporary tables:
EXECUTE migrate_to_lite WITH "shared_parent_type"='usertype_3'
,"execution_mode"='Run without Finalize'
Then, for step two, use the Finalize execution_mode to swap in the temporary tables and commit
the change:
EXECUTE migrate_to_lite WITH "shared_parent_type"='usertype_3'
,"execution_mode"='Finalize'
This example converts an existing standard type, test_payment_check, and all its objects, into a
lightweight type and a shareable type, test_payment_bank. Each lightweight object will have its own
private parent object. The parent type will take the attributes bank_code and routing, but the other
attributes will be part of the lightweight type.
In this example, there are already objects created of type test_payment_check. You can create the
type using the following command:
CREATE TYPE "test_payment_check" (
account integer,
check_number integer,
transaction_date date,
amount float,
bank_code integer,
routing integer
) WITH SUPERTYPE "dm_document" PUBLISH
You can also use the batch example program to create a number of objects for this example.
Use the following command to split the test_payment_check objects into lightweight objects of type
test_payment_check, and private parents of type test_payment_bank. The bank_code and routing
attribute values will be associated with the private parent, and the other attributes will be associated
with the lightweight objects. The attributes account and check_number of the (now lightweight) type
test_payment_check will be fulltext indexed:
EXECUTE migrate_to_lite WITH "source_type"='test_payment_check'
,"shared_parent_type"='test_payment_bank'
,"execution_mode"='Split and Finalize'
,"parent_attributes"='bank_code,routing'
,"ft_lite_add"='account,check_number'
The following example takes the materialized lightweight objects converted by the last example and
reparents them. Objects with check_numbers less than five are reparented to a separately created
test_payment_bank shareable parent, and the remaining materialized objects are reparented to
another separately created shareable parent:
EXECUTE "migrate_to_lite" WITH
"shared_parent_type"='test_payment_bank',"lightweight_type"='test_payment_check'
,"execution_mode"='Run and Finalize',"parent_sql_predicate"='check_number<5'
90
MIGRATE_TO_LITE Method
,"parent_id"='0925392d80001d5d'
,"default_parent_id"='0925392d80001d5e'
91
MIGRATE_TO_LITE Method
92
Chapter 9
Sample Program for Generating
Metadata for Partition Exchange
The following program is used as a step in the partition exchange example. It creates a shared parent
object in the repository, then creates five text files that contain the object metadata to be ingested into
the repository (all these objects are lightweight SysObjects that point to the shared parent object).
The text files will subsequently be loaded into offline tables in the repository database. After the
offline tables are loaded, they are exchanged for an online partition. After the partition exchange, the
lightweight objects are in the repository, and can be manipulated like any other lightweight objects.
This program is modified from an earlier version to support the additional single valued attribute,
i_other_contents, added to dmr_content in release 6.6.
Note: This program is provided as an example only. If you require assistance with writing programs
for partitioning, contact OpenText Global Technical Services.
/*
* loader.java
*
*
* This example assumes that you have created two types, test_payment_bank
* and test_payment_type. Here are the two DQL statements to create the types:
CREATE SHAREABLE TYPE test_payment_bank (
bank_code integer,
routing integer,
branch integer repeating
) WITH SUPERTYPE dm_sysobject PUBLISH
* This example also assumes that you have created an external store
* filestore_ex and that there is a check image TIFF file in the
* external store (use any TIFF to stand in for a check image).
*
* When you run this program, the repository name, username, password,
* number of docs to create, and the partition number to place them in,
* are passed to the program on the command line.
*
*/
package com.documentum.docs.archive.examples;
93
Sample Program for Generating Metadata for Partition Exchange
import com.documentum.com.DfClientX;
import com.documentum.com.IDfClientX;
import com.documentum.fc.client.*;
import com.documentum.fc.common.*;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.text.Format;
import java.util.Date;
import java.net.InetAddress;
Date start_time;
Date end_time;
IDfCollection r_id_col;
IDfCollection dmr_col;
try
{
start_time = new Date();
end_time = new Date();
start_time.setTime(System.currentTimeMillis());
System.out.println("Started @ " +
DateFormat.getDateTimeInstance().format(start_time));
parseCmdLine(args);
// Logon
sMgr = logOn(userName, password, docbaseName);
session = sMgr.getSession(docbaseName);
// Create Parent
parentObjId = CreateParent(session);
int amount = 0;
int maxIds = 10000; // max number of r_object_id's to retrieve at one time
// open files
PrintWriter dmiObjectType =
new PrintWriter(new FileWriter("dmiObjectType.txt"));
PrintWriter testPaymentCheckS =
94
Sample Program for Generating Metadata for Partition Exchange
// For this example, we are just using one image over and over again.
// In a real application, you would specify which content file
// goes with each child object.
String filePath = "c:/ExternalStore/paycheck.tif";
File file = new File(filePath);
95
Sample Program for Generating Metadata for Partition Exchange
r_id_col.close();
dmr_col.close();
}
dmiObjectType.close();
testPaymentCheckS.close();
testPaymentCheckR.close();
dmrContentS.close();
dmrContentR.close();
}
catch(Throwable e)
{
if(e instanceof DfException)
{
System.out.println("DFC Exception:");
String s = ((DfException)e).getStackTraceAsString();
System.out.println(s);
}
else
{
System.out.println("Non-DFC Exception");
e.printStackTrace();
}
}
finally
{
if (session != null)
sMgr.release(session);
end_time.setTime(System.currentTimeMillis());
System.out.println("Finished @ " +
DateFormat.getDateTimeInstance().format(end_time));
System.out.println("Elapsed " +
CalculateTimeDiff(start_time, end_time) + " sec");
}
}
96
Sample Program for Generating Metadata for Partition Exchange
sysObj.save();
return sysObj.getObjectId();
}
// This apply method will reserve a list of object IDs from the repository.
// Once reserved, the IDs will not be used by the repository, so you may want
// to set the number of reserved IDs large enough to cut down on the ID requests,
// but not so large as to use up IDs if the process fails, or there are leftover IDs
// when the objects are created. The equivalent API command is:
// apply,c,NULL,NEXT_ID_LIST,TAG,I,08,HOW_MANY,I,100
private static IDfCollection getNewObjectIds(IDfSession session, String tag,
String number) throws Throwable
{
IDfList args = new DfList();
IDfList types = new DfList();
IDfList values = new DfList();
args.appendString("TAG");
types.appendString("I");
values.appendString(tag);
args.appendString("HOW_MANY");
types.appendString("I");
values.appendString(number);
97
Sample Program for Generating Metadata for Partition Exchange
col.close();
return result;
}
col.close();
return result.toString();
}
col.close();
return result.toString();
}
diff_time.setTime(end_time.getTime() - start_time.getTime());
time_value = (end_time.getTime() - start_time.getTime()) / 1000;
return time_value;
}
/**
* void parseCmdLine(String[] args)
*
* Copies args[] variables into friendlier-named variables
*/
void parseCmdLine(String[] args)
{
if(args.length > 0)
{
for(int i = 0; i < args.length; ++i)
{
98
Sample Program for Generating Metadata for Partition Exchange
switch(i)
{
case DOCBASE: // 0
docbaseName = args[i];
break;
case USERNAME: // 1
userName = args[i];
break;
case PASSWORD: // 2
password = args[i];
break;
case NUMDOCS: // 3
numDocs = Integer.parseInt(args[i]);
break;
case PARTITION: // 4
partition = Integer.parseInt(args[i]);
break;
}
}
}
else
{
help();
System.exit(1); // you never return from this method
}
} //end: parseCmdLine(String[] args)
public static void main(String[] args)
{
new loader().begin(args);
}
private static void help()
{
String[] helpList =
{
"You must set arguments before executing this program.",
"Usage: java loader docbase user pwd numDocs partition",
"",
"Where: ",
" docbase Docbase name",
" user user name for the Docbase",
" pwd password",
" numDocs number of Docs to load",
" partition partition number to load into",
"",
"Example from command line:",
"",
" java loader train5 tuser1 password 10000 150",
};
for(int i = 0; i < helpList.length; ++i)
{
System.out.println(helpList[i]);
}
} //end: help()
static final int DOCBASE =0;
static final int USERNAME =1;
static final int PASSWORD =2;
static final int NUMDOCS =3;
static final int PARTITION =4;
}
99