2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 //%% (c) Copyright 1993, 1994 Hewlett-Packard Company
24 //%% (c) Copyright 1993, 1994 International Business Machines Corp.
25 //%% (c) Copyright 1993, 1994 Sun Microsystems, Inc.
26 //%% (c) Copyright 1993, 1994 Novell, Inc.
27 //%% $XConsortium: tt_db_object.C /main/3 1995/10/23 10:03:44 rswiston $
29 * tt_db_object.cc - Implement the TT DB server object class.
31 * Copyright (c) 1992 by Sun Microsystems, Inc.
35 #include "db/tt_db_create_objid.h"
36 #include "db/tt_db_key_utils.h"
37 #include "db/tt_db_network_path.h"
38 #include "db/tt_db_object_utils.h"
39 #include "db/tt_db_objid_to_key.h"
40 #include "db/tt_db_access.h"
41 #include "db/tt_db_property.h"
43 #define TT_DB_PROPS_CACHE_LEVEL_PROPERTY "_MODIFICATION_DATE"
45 _Tt_db_object::_Tt_db_object ()
47 setTtDBObjectDefaults();
50 _Tt_db_object::_Tt_db_object (const _Tt_string &objid)
52 setTtDBObjectDefaults();
55 getDBObjectHostnameFromID ();
56 if (isObjectInDatabase()) {
57 dbObjectPropertiesCacheLevel = -1;
59 setCurrentDBAccess ();
61 dbObjectDatabase->getObjectProperties(dbObjectID,
62 dbObjectPropertiesCacheLevel,
65 memoryObjectCreated = TRUE;
67 if ((dbResults == TT_DB_ERR_DB_CONNECTION_FAILED) ||
68 (dbResults == TT_DB_ERR_RPC_CONNECTION_FAILED)) {
69 dbHostnameGlobalMapRef.removeDB (dbObjectHostname);
73 dbResults = TT_DB_ERR_NO_SUCH_OBJECT;
77 void _Tt_db_object::setTtDBObjectDefaults ()
79 checkedDatabase = FALSE;
80 dbObjectAccess = new _Tt_db_access;
81 dbObjectCurrentAccess = new _Tt_db_access;
82 dbObjectProperties = new _Tt_db_property_list;
83 dbObjectPropertiesCacheLevel = -1;
85 forwardPointerFlag = FALSE;
86 memoryObjectCreated = FALSE;
89 _Tt_db_object::~_Tt_db_object ()
93 void _Tt_db_object::setCurrentAccess (const _Tt_db_access_ptr &access)
95 dbObjectCurrentAccess = access;
98 _Tt_db_access_ptr _Tt_db_object::getCurrentAccess () const
100 return dbObjectCurrentAccess;
103 _Tt_string _Tt_db_object::create (const _Tt_string &file)
106 return create(file, empty);
109 _Tt_string _Tt_db_object::create (const _Tt_string &file,
110 const _Tt_string &key)
112 if (!memoryObjectCreated) {
114 dbResults = TT_DB_ERR_ILLEGAL_FILE;
117 dbResults = createMemoryObject(file, key);
119 if (dbResults == TT_DB_OK) {
120 memoryObjectCreated = TRUE;
125 dbResults = TT_DB_ERR_OBJECT_EXISTS;
131 _Tt_db_results _Tt_db_object::write ()
133 if (!isObjectInDatabase()) {
134 dbResults = createDBObject();
137 _Tt_db_property_list_ptr properties_in_db;
139 // Find the cache level property and make sure it is up to date
140 // with the actual cache level
141 // XXX - This needs to be done with 4/93 DB servers. 10/93 DB servers
142 // will protect the cache level property on the DB server side.
143 _Tt_db_property_list_cursor properties_cursor (dbObjectProperties);
144 _Tt_string cache_level_bytes (sizeof (int));
146 while (properties_cursor.next ()) {
147 if (properties_cursor->name == TT_DB_PROPS_CACHE_LEVEL_PROPERTY) {
148 memcpy ((char *)cache_level_bytes,
149 &dbObjectPropertiesCacheLevel,
151 properties_cursor->values->flush ();
152 properties_cursor->values->append (cache_level_bytes);
156 setCurrentDBAccess ();
158 dbObjectDatabase->setObjectProperties(dbObjectID,
161 dbObjectPropertiesCacheLevel);
163 // If there was an update conflict, that means someone else wrote
164 // new props to the DB since this object had read its cached props.
165 // The _Tt_db_client object returns the properties currently in the
166 // database when this type of conflict occurs.
167 if (dbResults == TT_DB_ERR_UPDATE_CONFLICT) {
168 dbObjectProperties = properties_in_db;
172 return processDBResults();
175 _Tt_db_results _Tt_db_object::refresh ()
177 // Check if it is in the database and force it to find the object
178 // if it has been moved.
179 if (isObjectInDatabase(TRUE)) {
180 int cache_level = dbObjectPropertiesCacheLevel;
181 _Tt_db_property_list_ptr properties;
183 setCurrentDBAccess ();
184 dbResults = dbObjectDatabase->getObjectProperties(dbObjectID,
188 // Update the cache if the _Tt_db_client has new property data
189 if (cache_level > dbObjectPropertiesCacheLevel) {
190 dbObjectPropertiesCacheLevel = cache_level;
191 dbObjectProperties = properties;
195 dbResults = TT_DB_OK;
198 return processDBResults();
201 _Tt_db_results _Tt_db_object::remove ()
203 if (isObjectInDatabase()) {
204 setCurrentDBAccess ();
205 dbResults = dbObjectDatabase->removeObject(dbObjectID,
206 _Tt_string((char *)NULL));
208 if (dbResults == TT_DB_OK) {
209 setTtDBObjectDefaults();
213 dbResults = TT_DB_ERR_NO_SUCH_OBJECT;
216 return processDBResults();
219 _Tt_db_results _Tt_db_object::remove (const _Tt_string &forward_pointer)
221 if (isObjectInDatabase()) {
222 setCurrentDBAccess ();
223 dbResults = dbObjectDatabase->removeObject(dbObjectID, forward_pointer);
225 if (dbResults == TT_DB_OK) {
226 setTtDBObjectDefaults();
230 dbResults = TT_DB_ERR_NO_SUCH_OBJECT;
233 return processDBResults();
236 _Tt_string _Tt_db_object::copy (const _Tt_string &new_file)
238 _Tt_string new_objid;
240 if (!new_file.len()) {
241 dbResults = TT_DB_ERR_ILLEGAL_FILE;
245 if (isObjectInDatabase()) {
246 dbObjectFile = getFile();
248 _Tt_string new_local_file;
249 _Tt_string new_hostname;
250 _Tt_string new_partition;
251 _Tt_string new_file_network_path;
252 dbResults = _tt_db_network_path(new_file,
256 new_file_network_path);
258 if (dbResults == TT_DB_OK) {
259 // If we're not copying to the exact same file
260 if (dbObjectFile != new_file_network_path) {
261 _Tt_db_object_ptr new_object = new _Tt_db_object;
262 new_objid = new_object->create(new_file_network_path);
263 dbResults = new_object->getDBResults();
265 if ((dbResults == TT_DB_OK) && new_objid.len()) {
266 // Refresh the current object's info
267 dbResults = internalRefresh();
268 if (dbResults == TT_DB_OK) {
269 (void)new_object->setAccess(dbObjectAccess);
270 (void)new_object->setProperties(dbObjectProperties);
271 (void)new_object->setType(dbObjectType);
272 dbResults = new_object->write();
277 dbResults = TT_DB_ERR_SAME_OBJECT;
282 dbResults = TT_DB_ERR_NO_SUCH_OBJECT;
285 dbResults = processDBResults();
289 _Tt_string _Tt_db_object::move (const _Tt_string &new_file)
291 _Tt_string new_objid;
293 if (!new_file.len()) {
294 dbResults = TT_DB_ERR_ILLEGAL_FILE;
298 if (isObjectInDatabase()) {
299 dbObjectFile = getFile();
301 _Tt_string new_local_file;
302 _Tt_string new_hostname;
303 _Tt_string new_partition;
304 _Tt_string new_file_network_path;
305 dbResults = _tt_db_network_path(new_file,
309 new_file_network_path);
311 // If we're not moving to the exact same file
312 if (dbObjectFile != new_file_network_path) {
313 new_objid = makeEquivalentObjectID(new_hostname, new_partition);
315 if ((dbResults == TT_DB_OK) && new_objid.len()) {
316 // If the objids are still the same, we only need to change the
317 // object's file in the database...
318 if (dbObjectID == new_objid) {
319 dbResults = dbObjectDatabase->setObjectFile(dbObjectID,
320 new_file_network_path);
322 if (dbResults == TT_DB_OK) {
323 dbResults = TT_DB_WRN_SAME_OBJECT_ID;
326 // Different objids and therefore different partitions or hosts
328 _Tt_db_object_ptr new_object = new _Tt_db_object;
329 dbResults = new_object->setObjectID(new_objid);
331 // The new object should not exist, yet...
332 if (dbResults == TT_DB_ERR_NO_SUCH_OBJECT) {
333 new_object->dbObjectHostname = new_hostname;
334 new_object->dbObjectFile = new_file_network_path;
336 // Refresh the current object's info
337 dbResults = internalRefresh();
338 if (dbResults == TT_DB_OK) {
339 (void)new_object->setAccess(dbObjectAccess);
340 (void)new_object->setProperties(dbObjectProperties);
341 (void)new_object->setType(dbObjectType);
342 dbResults = new_object->write();
345 // If the new object already exists, then there is something
347 else if (dbResults == TT_DB_OK) {
348 dbResults = TT_DB_ERR_CORRUPT_DB;
351 if (dbResults == TT_DB_OK) {
352 // Remove current object from the DB and specify the new objid
353 // as the forward pointer.
354 dbResults = remove(new_objid);
356 if (dbResults == TT_DB_OK) {
357 setTtDBObjectDefaults();
358 dbResults = setObjectID(new_objid);
364 if (dbResults == TT_DB_OK) {
365 dbResults = TT_DB_ERR_ILLEGAL_OBJECT;
370 dbResults = TT_DB_ERR_SAME_OBJECT;
374 dbResults = TT_DB_ERR_NO_SUCH_OBJECT;
377 dbResults = processDBResults();
382 _Tt_db_object::setProperty (const _Tt_db_property_ptr &property)
384 if (property->name.len()) {
385 // See if a property with the same name exists...
386 bool_t found = FALSE;
387 _Tt_db_property_list_cursor properties_cursor(dbObjectProperties);
388 while (properties_cursor.next()) {
389 if (properties_cursor->name == property->name) {
395 // If a property with the same name exists...
397 // If the new property has no values specified, then just
398 // delete the old property...
399 if (property->is_empty()) {
400 properties_cursor.remove();
402 // Else, we actually want to set some values...
404 *properties_cursor = property;
407 // Else, no property with same name exists, just append the new
408 // property (if it's not empty)
409 else { if (!property->is_empty())
410 dbObjectProperties->append(property);
413 dbResults = TT_DB_OK;
416 dbResults = TT_DB_ERR_ILLEGAL_PROPERTY;
423 _Tt_db_object::setProperties (const _Tt_db_property_list_ptr &properties)
425 // Replace the old properties with the new list
426 dbObjectProperties = properties;
432 _Tt_db_object::addProperty (const _Tt_db_property_ptr &property,
435 if (property->name.len()) {
436 bool_t found = FALSE;
438 // See if a property with the same name exists in the cache
439 _Tt_db_property_list_cursor properties_cursor(dbObjectProperties);
440 while (properties_cursor.next()) {
441 if (properties_cursor->name == property->name) {
447 // If a property with the same name exists...
449 _Tt_string_list_cursor values_cursor(property->values);
451 // If a unique property name-value combinations are to be added...
453 _Tt_string_list_cursor cache_values_cursor(properties_cursor->values);
455 // Loop through the values to be added
456 while (values_cursor.next()) {
457 cache_values_cursor.reset();
459 // Compare versus values already in the cache
460 bool_t is_unique = TRUE;
461 while (cache_values_cursor.next()) {
462 if (*cache_values_cursor == *values_cursor) {
467 // If unique, append the value to the cache values
469 properties_cursor->values->append(*values_cursor);
473 // Else uniqueness is not a requirement...
475 while (values_cursor.next()) {
476 properties_cursor->values->append(*values_cursor);
480 dbResults = TT_DB_OK;
483 dbObjectProperties->append(property);
484 dbResults = TT_DB_OK;
488 dbResults = TT_DB_ERR_ILLEGAL_PROPERTY;
495 _Tt_db_object::deleteProperty (const _Tt_db_property_ptr &property)
497 if (isObjectInDatabase()) {
498 setCurrentDBAccess();
500 // Delete the property on the database immediately and refresh
501 // the cache with the latest and greatest. If the cache level
502 // here is not as high as the cache level in the DB, then the
505 dbObjectDatabase->deleteObjectProperty(dbObjectID,
508 dbObjectPropertiesCacheLevel);
511 dbResults = TT_DB_ERR_NO_SUCH_OBJECT;
514 return processDBResults();
517 _Tt_db_property_ptr _Tt_db_object::getProperty (const _Tt_string &name)
519 _Tt_db_property_ptr property;
522 bool_t found = FALSE;
523 _Tt_db_property_list_cursor properties_cursor(dbObjectProperties);
525 // See if a property matches the specified name
526 while (properties_cursor.next()) {
527 if (properties_cursor->name == name) {
534 property = *properties_cursor;
535 dbResults = TT_DB_OK;
538 dbResults = TT_DB_ERR_NO_SUCH_PROPERTY;
542 dbResults = TT_DB_ERR_ILLEGAL_PROPERTY;
548 _Tt_db_property_list_ptr _Tt_db_object::getProperties ()
550 dbResults = TT_DB_OK;
551 return dbObjectProperties;
554 _Tt_db_results _Tt_db_object::setType (const _Tt_string &type)
556 if (!isObjectInDatabase()) {
558 dbResults = TT_DB_OK;
561 dbResults = TT_DB_ERR_OTYPE_ALREADY_SET;
567 _Tt_string _Tt_db_object::getType ()
569 if (!dbObjectType.len() && isObjectInDatabase()) {
570 setCurrentDBAccess();
571 dbResults = dbObjectDatabase->getObjectType(dbObjectID, dbObjectType);
574 dbResults = TT_DB_OK;
577 dbResults = processDBResults();
581 _Tt_string _Tt_db_object::getFile ()
583 if (isObjectInDatabase()) {
584 setCurrentDBAccess();
585 dbResults = dbObjectDatabase->getObjectFile(dbObjectID, dbObjectFile);
588 dbResults = TT_DB_OK;
591 dbResults = processDBResults();
595 _Tt_db_results _Tt_db_object::setAccess (const _Tt_db_access_ptr &access)
597 dbObjectAccess = access;
599 if (isObjectInDatabase()) {
600 setCurrentDBAccess();
601 dbResults = dbObjectDatabase->setObjectAccess(dbObjectID, dbObjectAccess);
604 dbResults = TT_DB_OK;
607 return processDBResults();
610 _Tt_db_access_ptr _Tt_db_object::getAccess ()
612 if (isObjectInDatabase()) {
613 setCurrentDBAccess();
614 dbResults = dbObjectDatabase->getObjectAccess(dbObjectID, dbObjectAccess);
617 dbResults = TT_DB_OK;
620 dbResults = processDBResults();
621 return dbObjectAccess;
624 _Tt_string _Tt_db_object::getObjectKey () const
626 _Tt_string key_string;
628 if (dbObjectID.len()) {
629 key_string = _tt_db_objid_to_key(dbObjectID);
636 _Tt_db_object::createMemoryObject (const _Tt_string &file,
637 const _Tt_string& keystr)
639 _Tt_string local_file;
640 _Tt_string partition;
642 dbObjectID = (char *)NULL;
643 dbResults = _tt_db_network_path(file,
649 if (dbResults == TT_DB_OK) {
650 // Create a key for the new object,
651 // or use the passed-in one if present
654 key = new _Tt_db_key(keystr);
657 key = new _Tt_db_key();
660 dbObjectID = _tt_db_create_objid(key, "NFS",
661 dbObjectHostname, partition);
667 void _Tt_db_object::getDBObjectHostnameFromID ()
669 if (dbObjectID.len()) {
670 _Tt_string objid_string = dbObjectID;
671 _Tt_string temp_string;
673 // Get rid of the file system type
674 objid_string = objid_string.split(':', temp_string);
675 if (objid_string.len() && temp_string.len()) {
676 objid_string = objid_string.split(':', temp_string);
680 if (objid_string.len() && temp_string.len()) {
681 objid_string = objid_string.split(':', dbObjectHostname);
686 _Tt_db_results _Tt_db_object::createDBObject ()
688 if (dbObjectID.len()) {
689 if (dbObjectType.len()) {
690 dbObjectDatabase = dbHostnameGlobalMapRef.getDB(dbObjectHostname,
694 if (!dbObjectDatabase.is_null()) {
695 setCurrentDBAccess();
697 dbObjectDatabase->createObject (dbObjectFile,
702 dbObjectPropertiesCacheLevel);
704 dbObjectPropertiesCacheLevel = -1;
706 if (dbResults == TT_DB_OK) {
707 dbResults = internalRefresh ();
712 dbResults = TT_DB_ERR_NO_OTYPE;
716 dbResults = TT_DB_ERR_ILLEGAL_OBJECT;
722 _Tt_db_results _Tt_db_object::setObjectID (const _Tt_string &new_objid)
724 dbObjectID = new_objid;
725 getDBObjectHostnameFromID();
727 dbResults = (isObjectInDatabase(TRUE) ? TT_DB_OK :
728 TT_DB_ERR_NO_SUCH_OBJECT);
733 _Tt_db_object::makeEquivalentObjectID (const _Tt_string &hostname,
734 const _Tt_string &partition)
736 _Tt_string new_objid = _tt_db_objid_to_key(dbObjectID);
737 new_objid = new_objid.cat(":NFS");
738 new_objid = new_objid.cat(":").cat(hostname);
739 new_objid = new_objid.cat(":").cat(partition);
743 bool_t _Tt_db_object::isObjectInDatabase (bool_t force)
745 _Tt_string forward_pointer;
747 if ((!checkedDatabase || force) && dbObjectHostname.len()) {
748 // Get the DB connection for this objects DB host
749 dbObjectDatabase = dbHostnameGlobalMapRef.getDB(dbObjectHostname,
752 if (!dbObjectDatabase.is_null()) {
753 setCurrentDBAccess();
755 // See if the object is in the actual database and also check for
757 _Tt_string forward_pointer;
758 dbResults = dbObjectDatabase->isObjectInDatabase(dbObjectID,
762 // Either a failure or a forward pointer...
763 if (dbResults != TT_DB_OK) {
764 if (dbResults == TT_DB_ERR_NO_SUCH_OBJECT) {
765 dbHostnameGlobalMapRef.removeDB(dbObjectHostname);
766 dbObjectDatabase = (_Tt_db_client *)NULL;
767 dbResults = TT_DB_OK;
769 else if (dbResults == TT_DB_WRN_FORWARD_POINTER) {
770 // Change this objects ID to the forward pointer. The "setObjectID"
771 // member function will call "isObjectInDatabase" again and the
772 // forward pointer chain will eventually resolve to the final
773 // resting place of the object.
774 dbResults = setObjectID(forward_pointer);
775 forwardPointerFlag = TRUE;
779 checkedDatabase = TRUE;
782 return (dbObjectDatabase.is_null() ? FALSE : TRUE);
785 _Tt_db_results _Tt_db_object::internalRefresh ()
787 setCurrentDBAccess ();
789 dbObjectDatabase->getObjectProperties(dbObjectID,
790 dbObjectPropertiesCacheLevel,
793 if (dbResults == TT_DB_OK) {
794 dbResults = dbObjectDatabase->getObjectAccess(dbObjectID, dbObjectAccess);
797 if (dbResults == TT_DB_OK) {
798 dbResults = dbObjectDatabase->getObjectType(dbObjectID, dbObjectType);
804 _Tt_db_results _Tt_db_object::processDBResults ()
806 // If an RPC fails, assume the DB server went down and attemp to
808 if ((dbResults == TT_DB_ERR_DB_CONNECTION_FAILED) ||
809 (dbResults == TT_DB_ERR_RPC_CONNECTION_FAILED)) {
810 if (!dbObjectDatabase.is_null()) {
811 dbHostnameGlobalMapRef.removeDB(dbObjectHostname);
812 dbObjectDatabase = dbHostnameGlobalMapRef.getDB(dbObjectHostname,
818 // Else if the results were OK, but the forward pointer flag was set,
819 // return TT_WRN_FORWARD_POINTER
820 else if ((dbResults == TT_DB_OK) && forwardPointerFlag) {
821 forwardPointerFlag = FALSE;
822 dbResults = TT_DB_WRN_FORWARD_POINTER;