UCF Troubles

September 1, 2008

The UCF feature in Documentum seems to be a necessary evil.   I have had more complaints from our users regarding UCF than any other Documentum component.

The most common complaint is – It is DAMN slow to launch!!

I agree with the users.   Launching UCF in our organization’s environment takes around 50-70 seconds!!!

Imagine that you read around 20 documents at different times in the day and every time you want to read a document, you have to wait for 50 seconds. Can you imagine the wait while your browser displays a blank page?   No wonder the users complain about this.

After running several rounds of tests, we identified the factors that cause these really slow response times.
1) UCF uses Java JRE 1.5.x.  JRE needs time to initialize itself and load into memory before UCF kicks into action.  On a laptop with 1GB RAM and a reasonably fast CPU, JRE takes around 20-30 seconds to launch.
2) Another key factor is the presence of Anti-virus software on the user’s laptop.  Since AV will scan all the JRE related .jar files, the JRE initialization will be further slowed slowed down.

From our tests,  (Only the first operation after browser restart takes this long. Next operations should finish between 10-15 seconds)
- Export operation using UCF with Anti-virus takes around 50-70 seconds
- When Anti-virus is turned off, the Export operation takes around 35-45 seconds.

Some suggestions:
- Tune your anti-virus settings to exclude JRE folders and UCF folders
- Exclude anti-virus from scanning into .zip and archive files
- TEST with various settings

Here are some of the other common problems with UCF:
- JRE gets updated automatically when a new update is available from sun.com.  Sometimes this breaks the UCF.  Solution could be to try deleting all the UCF related folders and files in UCF folder (usually found in C:\Documents and Settings\Documentum\ucf)

Customers who are planning to use Documentum should test the performance of UCF in their environment.
1) Setup a pilot environment on a test server.  Access Webtop from a typical end-user PC and check the response times.  Make sure you are running anti-virus and any other software that are standard to your environment.  This is one way to ensure that the system performance will be acceptable to the end-users.
2) If you are planning to conduct any peformance testing and load testing, ensure that you specify that some scenarios include testing with UCF enabled.


Psuedo-Code for the User-rename Job

February 16, 2007

Start Here

 

Check if the NewUserName is same as the OldUserName, if so, don’t make any changes

Unlock (or only report) all sysobjects which are locked by the Old User. QueryStr = “query,c,select r_object_id from dm_sysobject ” & _

              “(all) where r_lock_owner = ‘” & DqlOldUserName & “‘”

Update all the sysObjects that have a reference to the OldUserName in the following attributes – “owner_name”, “acl_domain”, “r_creator_name”

In some cases, the Super-user may not have WRITE permissions to update the object.  In such cases, print an Error to the log

If the sysObject has been previously flagged as immutable, save the status of the object before making changes and then reset the object to its original immutable state

Save the last modifier (user name) to a variable and reset the last_modifier attribute to this variable after making the necessary changes to the object.  If the last_modifier was the OldUserName,  then update this with the NewUserName

Before calling any API methods make sure that the Single-quotes in the user-names are escaped by calling a function –  DmEscapeSingleQuotes(inputStr As String, byref msg_result As String)

Ensure that either NewUser or OldUser exist in the repository, else it is a FATAL error

If the NewUser Object does not exist just rename the existing user OldUser.
If the NewUser already exists, No need to update the dm_user objects, Just set a flag to delete the OldUser

Note: The OldUser object is really destroyed.  It is not set to be deactivated/disabled. 

Q) What is the implication on audit log entries because of this?

If the user object is successfully updated, we need to write to federation log.

Update Acl Objects

Get the list of ACL objects which have reference to the OldUser

DmQuery = dmAPIGet(“query,c,select r_object_id from dm_acl where ” & _

                      “owner_name = ‘” & DqlOldUserName & “‘ or ” & _

                      “any r_accessor_name = ‘” & DqlOldUserName & “‘”)

For Each ACL object,  Check if owner_name refers to OldUser, if so update it to NewUser

 Check if any of the r_accessor_name[i] values refer to OldUser, if so update them to NewUser

Update Alias Set Objects

Get the list of alias set objects that refer to OldUser:

DmQuery = dmAPIGet(“query,c,select r_object_id from dm_alias_set where ” & _

                      “owner_name = ‘” & DqlOldUserName & “‘ or ” & _

                      “any alias_value = ‘” & DqlOldUserName & “‘”)

For Each Alias Set object, 
 Check if owner_name refers to OldUser, if so update it to NewUser

 Check if alias_category[i] = 1.  This denotes a reference to a user

 Check if any of the alias_value [i] values refer to OldUser, if so update them to NewUser

If user’s default acl (acl_domain) is still pointing to the OldUser, then update it.

Update (or only report) sysobjects which are not locked

This call updates all the sysobjects that are not locked by ANY User, but whose attributes refer to the oldusername

QueryStr$ = “query,c,select r_object_id from ” & _

              “dm_sysobject (all) where ” & _

              “(owner_name = ‘” & DqlOldUserName & “‘ or ” & _

              “r_creator_name = ‘” & DqlOldUserName & “‘ or ” & _

              “r_modifier = ‘” & DqlOldUserName & “‘ or ” & _

              “acl_domain = ‘” & DqlOldUserName & “‘) and ” & _

              “r_lock_owner = ‘ ‘”

Update (or only report) sysobjects which are locked by ANY user (not just Old User)

  QueryStr$ = “query,c,select r_object_id from ” & _

              “dm_sysobject (all) where ” & _

              “(owner_name = ‘” & DqlOldUserName & “‘ or ” & _

              “r_creator_name = ‘” & DqlOldUserName & “‘ or ” & _

              “r_modifier = ‘” & DqlOldUserName & “‘ or ” & _

              “acl_domain = ‘” & DqlOldUserName & “‘) and ” & _

              “r_lock_owner <> ‘ ‘”

Update Workflow and related objects.

Update routers referencing the Old User. 

Note that router functionality is superseded in Documentum 4.0 and above by the workflow functionality. Documentum clients at version 4.0 and above won’t allow you to start new routers.  Depending on your version of Documentum, this may not be applicable

  DmQuery = dmAPIGet(“query,c,select r_object_id from dm_router (all) ” & _

              “where supervisor_name = ‘” & DqlOldUserName & “‘ or” & _

                     ” any task_owner = ‘” & DqlOldUserName & “‘ or” & _

                     ” any r_task_user = ‘” & DqlOldUserName & “‘”)

For Each Router object,

  Check if “supervisor_name” refers to OldUser if so, update it

  For Each of the task_owner values, if the attribute “task_owner[i]” refers to OldUser, update it

  For Each of the r_task_user values, if the attribute “r_task_user [i]” refers to OldUser, update it

Update activites referencing the Old User.

Check if there are any activity objects that refer to OldUserName

  DmQuery = dmAPIGet(“query,c,select r_object_id ” & _

        “from dm_activity (all) where any performer_name = ‘” & DqlOldUserName & “‘”)

If so , update all dm_activity objects using DQL:

    qry = “update dm_activity_r set performer_name = ‘” & DqlNewUserName & “‘ where performer_name = ‘” & DqlOldUserName &   

    //Directly call the DQL to run the query

    ret = dmAPIExec(“execsql,c,” & qry)

Update Workflow objects referencing OldUser

    change dm_workflow:

    qry = “update dm_workflow_s set r_creator_name = ‘” & DqlNewUserName & “‘ where r_creator_name = ‘” & DqlOldUserName &   

    qry = “update dm_workflow_s set supervisor_name = ‘” & DqlNewUserName & “‘ where supervisor_name = ‘” & DqlOldUserName & 

    qry = “update dm_workflow_r set r_performers = ‘” & DqlNewUserName & “‘ where r_performers = ‘” & DqlOldUserName & “‘”

    qry = “update dm_workflow_r set r_last_performer = ‘” & DqlNewUserName & “‘ where r_last_performer = ‘” & DqlOldUserName 

Update Workitem objects referencing OldUser:

Note: Work items are generated by Content Server from an activity object. Users cannot create work items.r_performer_name string(32) S Contains the name of an activity performer, or the owner name of the method if this is an automatic work item.r_ext_performer string(32) R Lists new performers to repeat the same activity. If a group name, only one work item is generated and any group member can  acquire the work item. 

   Change dmi_workitem:

  qry = “update dmi_workitem_s set r_performer_name = ‘” & DqlNewUserName & “‘ where r_performer_name = ‘” & DqlOldUserName

  qry = “update dmi_workitem_r set r_ext_performer = ‘” & DqlNewUserName & “‘ where r_ext_performer = ‘” & DqlOldUserName &

Update  dmi_queue_item objects referencing the Old User.

A queue item object stores information about an object placed on a user’s queue (Inbox).

   ‘ change dmi_queueitem:

    qry = “update dmi_queue_item_s set name = ‘” & DqlNewUserName & “‘ where name = ‘” & DqlOldUserName & “‘”

    qry = “update dmi_queue_item_s set sent_by = ‘” & DqlNewUserName & “‘ where sent_by = ‘” & DqlOldUserName & “‘”

    qry = “update dmi_queue_item_s set supervisor_name = ‘” & DqlNewUserName & “‘ where supervisor_name = ‘” & DqlOldUserName

    qry = “update dmi_queue_item_s set dequeued_by = ‘” & DqlNewUserName & “‘ where dequeued_by = ‘” & DqlOldUserName & “‘”

    qry = “update dmi_queue_item_s set sign_off_user = ‘” & DqlNewUserName & “‘ where sign_off_user = ‘” & DqlOldUserName &

 

Update GROUPS referencing the Old User.

DmQuery = dmAPIGet(“query,c,select r_object_id from dm_group where ” & _

                     “owner_name = ‘” & DqlOldUserName & “‘ or ” & _

                     “any users_names = ‘” & DqlOldUserName & “‘”)

For each group above, update owner_name attribute

There is an attribute called – group_admin CHAR(32).  This needs to updated if this refers to OldUser

The group has an array or user names.  If any of the user names refer to OldUser, update them (“users_names[i]“)

Deleting the OldUser object

Delete the old user object AFTER the references in group objects are  updated. Otherwise, the old user entries will be removed when the

 user object is destroyed.

    Call DmDeleteOldUserObj() {

      //The oldUserID is really – destroyed

      ret = dmAPIExec(“destroy,c,” & OldUserId)

    }

Update dmi_registry objects (reregister) 

A registry object contains information about a registered event.

Users can register to receive notification of an event’s occurrence. Users can also initiate auditing of events. Both actions generate registry objects.

The attribute user_name string(32) of dmi_registry contains the Name of the user that registered for the event or initiated auditing. This name should be updated

 ret = dmAPIExec(“execsql,c,update dmi_registry_s set user_name = ‘” & DqlNewUserName & “‘ ” & _

                ” where user_name = ‘” & DqlOldUserName & “‘”)

Other Objects

List all the dm_registered, dm_type and dmi_type_info objects referencing the old user. The script does not modify objects, administrators have to do it manually.

dm_registered

This represents a registered object contains information about an underlying RDBMS table that has been registered with Content Server.

DmQuery = dmAPIGet(“query,c,select r_object_id, object_name, ” & _

                     “table_name, table_owner from dm_registered ” & _

                     “where table_owner = ‘” & DqlOldUserName & “‘”)

dm_type

The following dm_type objects have owner_name attribute referencing user – OldUserName.  The script will not update the objects. You have to modify them manually.

A type object stores structural information about an object type in the repository.

There is minimal impact to leave this name as it is.  However if the user wants to update/modify this the type object, the Administrator will have to update this object

  DmQuery = dmAPIGet(“query,c,select r_object_id, name, super_name ” & _

         “from dm_type where “”" & “owner” & “”" = ‘” & DqlOldUserName & “‘”)

dmi_type_info

The following dmi_type_info objects have acl_domain attribute. The script will not update the objects. You have to modify them manually.

dmi_type_info  - A type info object stores non-structural information about an object type.  Storing non-structural  information separately from the type’s structure definition (the dm_type object) enhances the performance when a type is altered. This contains information about the ACLs, index settings etc.  The attribute – acl_domain may contain the user name.

DmQuery = dmAPIGet(“query,c,select r_object_id, r_type_name, ” & _

         “r_type_id, acl_domain, acl_name from dmi_type_info where ” & _

         “acl_domain = ‘” & DqlOldUserName & “‘”)

}

Note: I am not sure if this job is missing out any other objects. You may want to run a dql to find where else the user names are used.