Files
cdesktop/cde/lib/tt/lib/db/tt_db_object.C
2012-03-10 18:58:32 +00:00

827 lines
21 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these librararies and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
//%% (c) Copyright 1993, 1994 Hewlett-Packard Company
//%% (c) Copyright 1993, 1994 International Business Machines Corp.
//%% (c) Copyright 1993, 1994 Sun Microsystems, Inc.
//%% (c) Copyright 1993, 1994 Novell, Inc.
//%% $XConsortium: tt_db_object.C /main/3 1995/10/23 10:03:44 rswiston $
/*
* tt_db_object.cc - Implement the TT DB server object class.
*
* Copyright (c) 1992 by Sun Microsystems, Inc.
*
*/
#include "db/tt_db_create_objid.h"
#include "db/tt_db_key_utils.h"
#include "db/tt_db_network_path.h"
#include "db/tt_db_object_utils.h"
#include "db/tt_db_objid_to_key.h"
#include "db/tt_db_access.h"
#include "db/tt_db_property.h"
#define TT_DB_PROPS_CACHE_LEVEL_PROPERTY "_MODIFICATION_DATE"
_Tt_db_object::_Tt_db_object ()
{
setTtDBObjectDefaults();
}
_Tt_db_object::_Tt_db_object (const _Tt_string &objid)
{
setTtDBObjectDefaults();
dbObjectID = objid;
getDBObjectHostnameFromID ();
if (isObjectInDatabase()) {
dbObjectPropertiesCacheLevel = -1;
setCurrentDBAccess ();
dbResults =
dbObjectDatabase->getObjectProperties(dbObjectID,
dbObjectPropertiesCacheLevel,
dbObjectProperties);
memoryObjectCreated = TRUE;
if ((dbResults == TT_DB_ERR_DB_CONNECTION_FAILED) ||
(dbResults == TT_DB_ERR_RPC_CONNECTION_FAILED)) {
dbHostnameGlobalMapRef.removeDB (dbObjectHostname);
}
}
else {
dbResults = TT_DB_ERR_NO_SUCH_OBJECT;
}
}
void _Tt_db_object::setTtDBObjectDefaults ()
{
checkedDatabase = FALSE;
dbObjectAccess = new _Tt_db_access;
dbObjectCurrentAccess = new _Tt_db_access;
dbObjectProperties = new _Tt_db_property_list;
dbObjectPropertiesCacheLevel = -1;
dbResults = TT_DB_OK;
forwardPointerFlag = FALSE;
memoryObjectCreated = FALSE;
}
_Tt_db_object::~_Tt_db_object ()
{
}
void _Tt_db_object::setCurrentAccess (const _Tt_db_access_ptr &access)
{
dbObjectCurrentAccess = access;
}
_Tt_db_access_ptr _Tt_db_object::getCurrentAccess () const
{
return dbObjectCurrentAccess;
}
_Tt_string _Tt_db_object::create (const _Tt_string &file)
{
_Tt_string empty;
return create(file, empty);
}
_Tt_string _Tt_db_object::create (const _Tt_string &file,
const _Tt_string &key)
{
if (!memoryObjectCreated) {
if (!file.len()) {
dbResults = TT_DB_ERR_ILLEGAL_FILE;
}
else {
dbResults = createMemoryObject(file, key);
if (dbResults == TT_DB_OK) {
memoryObjectCreated = TRUE;
}
}
}
else {
dbResults = TT_DB_ERR_OBJECT_EXISTS;
}
return dbObjectID;
}
_Tt_db_results _Tt_db_object::write ()
{
if (!isObjectInDatabase()) {
dbResults = createDBObject();
}
else {
_Tt_db_property_list_ptr properties_in_db;
// Find the cache level property and make sure it is up to date
// with the actual cache level
// XXX - This needs to be done with 4/93 DB servers. 10/93 DB servers
// will protect the cache level property on the DB server side.
_Tt_db_property_list_cursor properties_cursor (dbObjectProperties);
_Tt_string cache_level_bytes (sizeof (int));
while (properties_cursor.next ()) {
if (properties_cursor->name == TT_DB_PROPS_CACHE_LEVEL_PROPERTY) {
memcpy ((char *)cache_level_bytes,
&dbObjectPropertiesCacheLevel,
sizeof (int));
properties_cursor->values->flush ();
properties_cursor->values->append (cache_level_bytes);
}
}
setCurrentDBAccess ();
dbResults =
dbObjectDatabase->setObjectProperties(dbObjectID,
dbObjectProperties,
properties_in_db,
dbObjectPropertiesCacheLevel);
// If there was an update conflict, that means someone else wrote
// new props to the DB since this object had read its cached props.
// The _Tt_db_client object returns the properties currently in the
// database when this type of conflict occurs.
if (dbResults == TT_DB_ERR_UPDATE_CONFLICT) {
dbObjectProperties = properties_in_db;
}
}
return processDBResults();
}
_Tt_db_results _Tt_db_object::refresh ()
{
// Check if it is in the database and force it to find the object
// if it has been moved.
if (isObjectInDatabase(TRUE)) {
int cache_level = dbObjectPropertiesCacheLevel;
_Tt_db_property_list_ptr properties;
setCurrentDBAccess ();
dbResults = dbObjectDatabase->getObjectProperties(dbObjectID,
cache_level,
properties);
// Update the cache if the _Tt_db_client has new property data
if (cache_level > dbObjectPropertiesCacheLevel) {
dbObjectPropertiesCacheLevel = cache_level;
dbObjectProperties = properties;
}
}
else {
dbResults = TT_DB_OK;
}
return processDBResults();
}
_Tt_db_results _Tt_db_object::remove ()
{
if (isObjectInDatabase()) {
setCurrentDBAccess ();
dbResults = dbObjectDatabase->removeObject(dbObjectID,
_Tt_string((char *)NULL));
if (dbResults == TT_DB_OK) {
setTtDBObjectDefaults();
}
}
else {
dbResults = TT_DB_ERR_NO_SUCH_OBJECT;
}
return processDBResults();
}
_Tt_db_results _Tt_db_object::remove (const _Tt_string &forward_pointer)
{
if (isObjectInDatabase()) {
setCurrentDBAccess ();
dbResults = dbObjectDatabase->removeObject(dbObjectID, forward_pointer);
if (dbResults == TT_DB_OK) {
setTtDBObjectDefaults();
}
}
else {
dbResults = TT_DB_ERR_NO_SUCH_OBJECT;
}
return processDBResults();
}
_Tt_string _Tt_db_object::copy (const _Tt_string &new_file)
{
_Tt_string new_objid;
if (!new_file.len()) {
dbResults = TT_DB_ERR_ILLEGAL_FILE;
return new_objid;
}
if (isObjectInDatabase()) {
dbObjectFile = getFile();
_Tt_string new_local_file;
_Tt_string new_hostname;
_Tt_string new_partition;
_Tt_string new_file_network_path;
dbResults = _tt_db_network_path(new_file,
new_local_file,
new_hostname,
new_partition,
new_file_network_path);
if (dbResults == TT_DB_OK) {
// If we're not copying to the exact same file
if (dbObjectFile != new_file_network_path) {
_Tt_db_object_ptr new_object = new _Tt_db_object;
new_objid = new_object->create(new_file_network_path);
dbResults = new_object->getDBResults();
if ((dbResults == TT_DB_OK) && new_objid.len()) {
// Refresh the current object's info
dbResults = internalRefresh();
if (dbResults == TT_DB_OK) {
(void)new_object->setAccess(dbObjectAccess);
(void)new_object->setProperties(dbObjectProperties);
(void)new_object->setType(dbObjectType);
dbResults = new_object->write();
}
}
}
else {
dbResults = TT_DB_ERR_SAME_OBJECT;
}
}
}
else {
dbResults = TT_DB_ERR_NO_SUCH_OBJECT;
}
dbResults = processDBResults();
return new_objid;
}
_Tt_string _Tt_db_object::move (const _Tt_string &new_file)
{
_Tt_string new_objid;
if (!new_file.len()) {
dbResults = TT_DB_ERR_ILLEGAL_FILE;
return new_objid;
}
if (isObjectInDatabase()) {
dbObjectFile = getFile();
_Tt_string new_local_file;
_Tt_string new_hostname;
_Tt_string new_partition;
_Tt_string new_file_network_path;
dbResults = _tt_db_network_path(new_file,
new_local_file,
new_hostname,
new_partition,
new_file_network_path);
// If we're not moving to the exact same file
if (dbObjectFile != new_file_network_path) {
new_objid = makeEquivalentObjectID(new_hostname, new_partition);
if ((dbResults == TT_DB_OK) && new_objid.len()) {
// If the objids are still the same, we only need to change the
// object's file in the database...
if (dbObjectID == new_objid) {
dbResults = dbObjectDatabase->setObjectFile(dbObjectID,
new_file_network_path);
if (dbResults == TT_DB_OK) {
dbResults = TT_DB_WRN_SAME_OBJECT_ID;
}
}
// Different objids and therefore different partitions or hosts
else {
_Tt_db_object_ptr new_object = new _Tt_db_object;
dbResults = new_object->setObjectID(new_objid);
// The new object should not exist, yet...
if (dbResults == TT_DB_ERR_NO_SUCH_OBJECT) {
new_object->dbObjectHostname = new_hostname;
new_object->dbObjectFile = new_file_network_path;
// Refresh the current object's info
dbResults = internalRefresh();
if (dbResults == TT_DB_OK) {
(void)new_object->setAccess(dbObjectAccess);
(void)new_object->setProperties(dbObjectProperties);
(void)new_object->setType(dbObjectType);
dbResults = new_object->write();
}
}
// If the new object already exists, then there is something
// weird going on...
else if (dbResults == TT_DB_OK) {
dbResults = TT_DB_ERR_CORRUPT_DB;
}
if (dbResults == TT_DB_OK) {
// Remove current object from the DB and specify the new objid
// as the forward pointer.
dbResults = remove(new_objid);
if (dbResults == TT_DB_OK) {
setTtDBObjectDefaults();
dbResults = setObjectID(new_objid);
}
}
}
}
else {
if (dbResults == TT_DB_OK) {
dbResults = TT_DB_ERR_ILLEGAL_OBJECT;
}
}
}
else {
dbResults = TT_DB_ERR_SAME_OBJECT;
}
}
else {
dbResults = TT_DB_ERR_NO_SUCH_OBJECT;
}
dbResults = processDBResults();
return new_objid;
}
_Tt_db_results
_Tt_db_object::setProperty (const _Tt_db_property_ptr &property)
{
if (property->name.len()) {
// See if a property with the same name exists...
bool_t found = FALSE;
_Tt_db_property_list_cursor properties_cursor(dbObjectProperties);
while (properties_cursor.next()) {
if (properties_cursor->name == property->name) {
found = TRUE;
break;
}
}
// If a property with the same name exists...
if (found) {
// If the new property has no values specified, then just
// delete the old property...
if (property->is_empty()) {
properties_cursor.remove();
}
// Else, we actually want to set some values...
else {
*properties_cursor = property;
}
}
// Else, no property with same name exists, just append the new
// property (if it's not empty)
else { if (!property->is_empty())
dbObjectProperties->append(property);
}
dbResults = TT_DB_OK;
}
else {
dbResults = TT_DB_ERR_ILLEGAL_PROPERTY;
}
return dbResults;
}
_Tt_db_results
_Tt_db_object::setProperties (const _Tt_db_property_list_ptr &properties)
{
// Replace the old properties with the new list
dbObjectProperties = properties;
return dbResults;
}
_Tt_db_results
_Tt_db_object::addProperty (const _Tt_db_property_ptr &property,
bool_t unique)
{
if (property->name.len()) {
bool_t found = FALSE;
// See if a property with the same name exists in the cache
_Tt_db_property_list_cursor properties_cursor(dbObjectProperties);
while (properties_cursor.next()) {
if (properties_cursor->name == property->name) {
found = TRUE;
break;
}
}
// If a property with the same name exists...
if (found) {
_Tt_string_list_cursor values_cursor(property->values);
// If a unique property name-value combinations are to be added...
if (unique) {
_Tt_string_list_cursor cache_values_cursor(properties_cursor->values);
// Loop through the values to be added
while (values_cursor.next()) {
cache_values_cursor.reset();
// Compare versus values already in the cache
bool_t is_unique = TRUE;
while (cache_values_cursor.next()) {
if (*cache_values_cursor == *values_cursor) {
is_unique = FALSE;
}
}
// If unique, append the value to the cache values
if (is_unique) {
properties_cursor->values->append(*values_cursor);
}
}
}
// Else uniqueness is not a requirement...
else {
while (values_cursor.next()) {
properties_cursor->values->append(*values_cursor);
}
}
dbResults = TT_DB_OK;
}
else {
dbObjectProperties->append(property);
dbResults = TT_DB_OK;
}
}
else {
dbResults = TT_DB_ERR_ILLEGAL_PROPERTY;
}
return dbResults;
}
_Tt_db_results
_Tt_db_object::deleteProperty (const _Tt_db_property_ptr &property)
{
if (isObjectInDatabase()) {
setCurrentDBAccess();
// Delete the property on the database immediately and refresh
// the cache with the latest and greatest. If the cache level
// here is not as high as the cache level in the DB, then the
// delete will fail.
dbResults =
dbObjectDatabase->deleteObjectProperty(dbObjectID,
property,
dbObjectProperties,
dbObjectPropertiesCacheLevel);
}
else {
dbResults = TT_DB_ERR_NO_SUCH_OBJECT;
}
return processDBResults();
}
_Tt_db_property_ptr _Tt_db_object::getProperty (const _Tt_string &name)
{
_Tt_db_property_ptr property;
if (name.len()) {
bool_t found = FALSE;
_Tt_db_property_list_cursor properties_cursor(dbObjectProperties);
// See if a property matches the specified name
while (properties_cursor.next()) {
if (properties_cursor->name == name) {
found = TRUE;
break;
}
}
if (found) {
property = *properties_cursor;
dbResults = TT_DB_OK;
}
else {
dbResults = TT_DB_ERR_NO_SUCH_PROPERTY;
}
}
else {
dbResults = TT_DB_ERR_ILLEGAL_PROPERTY;
}
return property;
}
_Tt_db_property_list_ptr _Tt_db_object::getProperties ()
{
dbResults = TT_DB_OK;
return dbObjectProperties;
}
_Tt_db_results _Tt_db_object::setType (const _Tt_string &type)
{
if (!isObjectInDatabase()) {
dbObjectType = type;
dbResults = TT_DB_OK;
}
else {
dbResults = TT_DB_ERR_OTYPE_ALREADY_SET;
}
return dbResults;
}
_Tt_string _Tt_db_object::getType ()
{
if (!dbObjectType.len() && isObjectInDatabase()) {
setCurrentDBAccess();
dbResults = dbObjectDatabase->getObjectType(dbObjectID, dbObjectType);
}
else {
dbResults = TT_DB_OK;
}
dbResults = processDBResults();
return dbObjectType;
}
_Tt_string _Tt_db_object::getFile ()
{
if (isObjectInDatabase()) {
setCurrentDBAccess();
dbResults = dbObjectDatabase->getObjectFile(dbObjectID, dbObjectFile);
}
else {
dbResults = TT_DB_OK;
}
dbResults = processDBResults();
return dbObjectFile;
}
_Tt_db_results _Tt_db_object::setAccess (const _Tt_db_access_ptr &access)
{
dbObjectAccess = access;
if (isObjectInDatabase()) {
setCurrentDBAccess();
dbResults = dbObjectDatabase->setObjectAccess(dbObjectID, dbObjectAccess);
}
else {
dbResults = TT_DB_OK;
}
return processDBResults();
}
_Tt_db_access_ptr _Tt_db_object::getAccess ()
{
if (isObjectInDatabase()) {
setCurrentDBAccess();
dbResults = dbObjectDatabase->getObjectAccess(dbObjectID, dbObjectAccess);
}
else {
dbResults = TT_DB_OK;
}
dbResults = processDBResults();
return dbObjectAccess;
}
_Tt_string _Tt_db_object::getObjectKey () const
{
_Tt_string key_string;
if (dbObjectID.len()) {
key_string = _tt_db_objid_to_key(dbObjectID);
}
return key_string;
}
_Tt_db_results
_Tt_db_object::createMemoryObject (const _Tt_string &file,
const _Tt_string& keystr)
{
_Tt_string local_file;
_Tt_string partition;
dbObjectID = (char *)NULL;
dbResults = _tt_db_network_path(file,
local_file,
dbObjectHostname,
partition,
dbObjectFile);
if (dbResults == TT_DB_OK) {
// Create a key for the new object,
// or use the passed-in one if present
_Tt_db_key_ptr key;
if (keystr.len()) {
key = new _Tt_db_key(keystr);
}
else {
key = new _Tt_db_key();
}
dbObjectID = _tt_db_create_objid(key, "NFS",
dbObjectHostname, partition);
}
return dbResults;
}
void _Tt_db_object::getDBObjectHostnameFromID ()
{
if (dbObjectID.len()) {
_Tt_string objid_string = dbObjectID;
_Tt_string temp_string;
// Get rid of the file system type
objid_string = objid_string.split(':', temp_string);
if (objid_string.len() && temp_string.len()) {
objid_string = objid_string.split(':', temp_string);
}
// Get the hostname
if (objid_string.len() && temp_string.len()) {
objid_string = objid_string.split(':', dbObjectHostname);
}
}
}
_Tt_db_results _Tt_db_object::createDBObject ()
{
if (dbObjectID.len()) {
if (dbObjectType.len()) {
dbObjectDatabase = dbHostnameGlobalMapRef.getDB(dbObjectHostname,
dbObjectHostname,
dbResults);
if (!dbObjectDatabase.is_null()) {
setCurrentDBAccess();
dbResults =
dbObjectDatabase->createObject (dbObjectFile,
dbObjectID,
dbObjectType,
dbObjectProperties,
dbObjectAccess,
dbObjectPropertiesCacheLevel);
dbObjectPropertiesCacheLevel = -1;
if (dbResults == TT_DB_OK) {
dbResults = internalRefresh ();
}
}
}
else {
dbResults = TT_DB_ERR_NO_OTYPE;
}
}
else {
dbResults = TT_DB_ERR_ILLEGAL_OBJECT;
}
return dbResults;
}
_Tt_db_results _Tt_db_object::setObjectID (const _Tt_string &new_objid)
{
dbObjectID = new_objid;
getDBObjectHostnameFromID();
dbResults = (isObjectInDatabase(TRUE) ? TT_DB_OK :
TT_DB_ERR_NO_SUCH_OBJECT);
return dbResults;
}
_Tt_string
_Tt_db_object::makeEquivalentObjectID (const _Tt_string &hostname,
const _Tt_string &partition)
{
_Tt_string new_objid = _tt_db_objid_to_key(dbObjectID);
new_objid = new_objid.cat(":NFS");
new_objid = new_objid.cat(":").cat(hostname);
new_objid = new_objid.cat(":").cat(partition);
return new_objid;
}
bool_t _Tt_db_object::isObjectInDatabase (bool_t force)
{
_Tt_string forward_pointer;
if ((!checkedDatabase || force) && dbObjectHostname.len()) {
// Get the DB connection for this objects DB host
dbObjectDatabase = dbHostnameGlobalMapRef.getDB(dbObjectHostname,
dbObjectHostname,
dbResults);
if (!dbObjectDatabase.is_null()) {
setCurrentDBAccess();
// See if the object is in the actual database and also check for
// a forward pointer
_Tt_string forward_pointer;
dbResults = dbObjectDatabase->isObjectInDatabase(dbObjectID,
forward_pointer);
}
// Either a failure or a forward pointer...
if (dbResults != TT_DB_OK) {
if (dbResults == TT_DB_ERR_NO_SUCH_OBJECT) {
dbHostnameGlobalMapRef.removeDB(dbObjectHostname);
dbObjectDatabase = (_Tt_db_client *)NULL;
dbResults = TT_DB_OK;
}
else if (dbResults == TT_DB_WRN_FORWARD_POINTER) {
// Change this objects ID to the forward pointer. The "setObjectID"
// member function will call "isObjectInDatabase" again and the
// forward pointer chain will eventually resolve to the final
// resting place of the object.
dbResults = setObjectID(forward_pointer);
forwardPointerFlag = TRUE;
}
}
checkedDatabase = TRUE;
}
return (dbObjectDatabase.is_null() ? FALSE : TRUE);
}
_Tt_db_results _Tt_db_object::internalRefresh ()
{
setCurrentDBAccess ();
dbResults =
dbObjectDatabase->getObjectProperties(dbObjectID,
dbObjectPropertiesCacheLevel,
dbObjectProperties);
if (dbResults == TT_DB_OK) {
dbResults = dbObjectDatabase->getObjectAccess(dbObjectID, dbObjectAccess);
}
if (dbResults == TT_DB_OK) {
dbResults = dbObjectDatabase->getObjectType(dbObjectID, dbObjectType);
}
return dbResults;
}
_Tt_db_results _Tt_db_object::processDBResults ()
{
// If an RPC fails, assume the DB server went down and attemp to
// reconnect to it
if ((dbResults == TT_DB_ERR_DB_CONNECTION_FAILED) ||
(dbResults == TT_DB_ERR_RPC_CONNECTION_FAILED)) {
if (!dbObjectDatabase.is_null()) {
dbHostnameGlobalMapRef.removeDB(dbObjectHostname);
dbObjectDatabase = dbHostnameGlobalMapRef.getDB(dbObjectHostname,
dbObjectHostname,
dbResults);
}
}
// Else if the results were OK, but the forward pointer flag was set,
// return TT_WRN_FORWARD_POINTER
else if ((dbResults == TT_DB_OK) && forwardPointerFlag) {
forwardPointerFlag = FALSE;
dbResults = TT_DB_WRN_FORWARD_POINTER;
}
return dbResults;
}