- •Advanced CORBA® Programming with C++
- •Review
- •Dedication
- •Preface
- •Prerequisites
- •Scope of this Book
- •Acknowledgments
- •Chapter 1. Introduction
- •1.1 Introduction
- •1.2 Organization of the Book
- •1.3 CORBA Version
- •1.4 Typographical Conventions
- •1.5 Source Code Examples
- •1.6 Vendor Dependencies
- •1.7 Contacting the Authors
- •Part I: Introduction to CORBA
- •Chapter 2. An Overview of CORBA
- •2.1 Introduction
- •2.2 The Object Management Group
- •2.3 Concepts and Terminology
- •2.4 CORBA Features
- •2.5 Request Invocation
- •2.6 General CORBA Application Development
- •2.7 Summary
- •Chapter 3. A Minimal CORBA Application
- •3.1 Chapter Overview
- •3.2 Writing and Compiling an IDL Definition
- •3.3 Writing and Compiling a Server
- •3.4 Writing and Compiling a Client
- •3.5 Running Client and Server
- •3.6 Summary
- •Part II: Core CORBA
- •Chapter 4. The OMG Interface Definition Language
- •4.1 Chapter Overview
- •4.2 Introduction
- •4.3 Compilation
- •4.4 Source Files
- •4.5 Lexical Rules
- •4.6 Basic IDL Types
- •4.7 User-Defined Types
- •4.8 Interfaces and Operations
- •4.9 User Exceptions
- •4.10 System Exceptions
- •4.11 System Exceptions or User Exceptions?
- •4.12 Oneway Operations
- •4.13 Contexts
- •4.14 Attributes
- •4.15 Modules
- •4.16 Forward Declarations
- •4.17 Inheritance
- •4.18 Names and Scoping
- •4.19 Repository Identifiers and pragma Directives
- •4.20 Standard Include Files
- •4.21 Recent IDL Extensions
- •4.22 Summary
- •Chapter 5. IDL for a Climate Control System
- •5.1 Chapter Overview
- •5.2 The Climate Control System
- •5.3 IDL for the Climate Control System
- •5.4 The Complete Specification
- •Chapter 6. Basic IDL-to-C++ Mapping
- •6.1 Chapter Overview
- •6.2 Introduction
- •6.3 Mapping for Identifiers
- •6.4 Mapping for Modules
- •6.5 The CORBA Module
- •6.6 Mapping for Basic Types
- •6.7 Mapping for Constants
- •6.8 Mapping for Enumerated Types
- •6.9 Variable-Length Types and _var Types
- •6.10 The String_var Wrapper Class
- •6.11 Mapping for Wide Strings
- •6.12 Mapping for Fixed-Point Types
- •6.13 Mapping for Structures
- •6.14 Mapping for Sequences
- •6.15 Mapping for Arrays
- •6.16 Mapping for Unions
- •6.17 Mapping for Recursive Structures and Unions
- •6.18 Mapping for Type Definitions
- •6.19 User-Defined Types and _var Classes
- •6.20 Summary
- •Chapter 7. Client-Side C++ Mapping
- •7.1 Chapter Overview
- •7.2 Introduction
- •7.3 Mapping for Interfaces
- •7.4 Object Reference Types
- •7.5 Life Cycle of Object References
- •7.6 Semantics of _ptr References
- •7.7 Pseudo-Objects
- •7.8 ORB Initialization
- •7.9 Initial References
- •7.10 Stringified References
- •7.11 The Object Pseudo-Interface
- •7.12 _var References
- •7.13 Mapping for Operations and Attributes
- •7.14 Parameter Passing Rules
- •7.15 Mapping for Exceptions
- •7.16 Mapping for Contexts
- •7.17 Summary
- •Chapter 8. Developing a Client for the Climate Control System
- •8.1 Chapter Overview
- •8.2 Introduction
- •8.3 Overall Client Structure
- •8.4 Included Files
- •8.5 Helper Functions
- •8.6 The main Program
- •8.7 The Complete Client Code
- •8.8 Summary
- •Chapter 9. Server-Side C++ Mapping
- •9.1 Chapter Overview
- •9.2 Introduction
- •9.3 Mapping for Interfaces
- •9.4 Servant Classes
- •9.5 Object Incarnation
- •9.6 Server main
- •9.7 Parameter Passing Rules
- •9.8 Raising Exceptions
- •9.9 Tie Classes
- •9.10 Summary
- •Chapter 10. Developing a Server for the Climate Control System
- •10.1 Chapter Overview
- •10.2 Introduction
- •10.3 The Instrument Control Protocol API
- •10.4 Designing the Thermometer Servant Class
- •10.5 Implementing the Thermometer Servant Class
- •10.6 Designing the Thermostat Servant Class
- •10.7 Implementing the Thermostat Servant Class
- •10.8 Designing the Controller Servant Class
- •10.9 Implementing the Controller Servant Class
- •10.10 Implementing the Server main Function
- •10.11 The Complete Server Code
- •10.12 Summary
- •Chapter 11. The Portable Object Adapter
- •11.1 Chapter Overview
- •11.2 Introduction
- •11.3 POA Fundamentals
- •11.4 POA Policies
- •11.5 POA Creation
- •11.6 Servant IDL Type
- •11.7 Object Creation and Activation
- •11.8 Reference, ObjectId, and Servant
- •11.9 Object Deactivation
- •11.10 Request Flow Control
- •11.11 ORB Event Handling
- •11.12 POA Activation
- •11.13 POA Destruction
- •11.14 Applying POA Policies
- •11.15 Summary
- •Chapter 12. Object Life Cycle
- •12.1 Chapter Overview
- •12.2 Introduction
- •12.3 Object Factories
- •12.4 Destroying, Copying, and Moving Objects
- •12.5 A Critique of the Life Cycle Service
- •12.6 The Evictor Pattern
- •12.7 Garbage Collection of Servants
- •12.8 Garbage Collection of CORBA Objects
- •12.9 Summary
- •Part III: CORBA Mechanisms
- •Chapter 13. GIOP, IIOP, and IORs
- •13.1 Chapter Overview
- •13.2 An Overview of GIOP
- •13.3 Common Data Representation
- •13.4 GIOP Message Formats
- •13.5 GIOP Connection Management
- •13.6 Detecting Disorderly Shutdown
- •13.7 An Overview of IIOP
- •13.8 Structure of an IOR
- •13.9 Bidirectional IIOP
- •13.10 Summary
- •14.1 Chapter Overview
- •14.2 Binding Modes
- •14.3 Direct Binding
- •14.4 Indirect Binding via an Implementation Repository
- •14.5 Migration, Reliability, Performance, and Scalability
- •14.6 Activation Modes
- •14.7 Race Conditions
- •14.8 Security Considerations
- •14.9 Summary
- •Part VI: Dynamic CORBA
- •Chapter 15 C++ Mapping for Type any
- •15.1 Chapter Overview
- •15.2 Introduction
- •15.3 Type any C++ Mapping
- •15.4 Pitfalls in Type Definitions
- •15.5 Summary
- •Chapter 16. Type Codes
- •16.1 Chapter Overview
- •16.2 Introduction
- •16.3 The TypeCode Pseudo-Object
- •16.4 C++ Mapping for the TypeCode Pseudo-Object
- •16.5 Type Code Comparisons
- •16.6 Type Code Constants
- •16.7 Type Code Comparison for Type any
- •16.8 Creating Type Codes Dynamically
- •16.9 Summary
- •Chapter 17. Type DynAny
- •17.1 Chapter Overview
- •17.2 Introduction
- •17.3 The DynAny Interface
- •17.4 C++ Mapping for DynAny
- •17.5 Using DynAny for Generic Display
- •17.6 Obtaining Type Information
- •17.7 Summary
- •Part V: CORBAservices
- •Chapter 18. The OMG Naming Service
- •18.1 Chapter Overview
- •18.2 Introduction
- •18.3 Basic Concepts
- •18.4 Structure of the Naming Service IDL
- •18.5 Semantics of Names
- •18.6 Naming Context IDL
- •18.7 Iterators
- •18.8 Pitfalls in the Naming Service
- •18.9 The Names Library
- •18.10 Naming Service Tools
- •18.11 What to Advertise
- •18.12 When to Advertise
- •18.13 Federated Naming
- •18.14 Adding Naming to the Climate Control System
- •18.15 Summary
- •Chapter 19. The OMG Trading Service
- •19.1 Chapter Overview
- •19.2 Introduction
- •19.3 Trading Concepts and Terminology
- •19.4 IDL Overview
- •19.5 The Service Type Repository
- •19.6 The Trader Interfaces
- •19.7 Exporting Service Offers
- •19.8 Withdrawing Service Offers
- •19.9 Modifying Service Offers
- •19.10 The Trader Constraint Language
- •19.11 Importing Service Offers
- •19.12 Bulk Withdrawal
- •19.13 The Admin Interface
- •19.14 Inspecting Service Offers
- •19.15 Exporting Dynamic Properties
- •19.16 Trader Federation
- •19.17 Trader Tools
- •19.18 Architectural Considerations
- •19.19 What to Advertise
- •19.20 Avoiding Duplicate Service Offers
- •19.21 Adding Trading to the Climate Control System
- •19.22 Summary
- •Chapter 20. The OMG Event Service
- •20.1 Chapter Overview
- •20.2 Introduction
- •20.3 Distributed Callbacks
- •20.4 Event Service Basics
- •20.5 Event Service Interfaces
- •20.6 Implementing Consumers and Suppliers
- •20.7 Choosing an Event Model
- •20.8 Event Service Limitations
- •20.9 Summary
- •Part VI: Power CORBA
- •Chapter 21. Multithreaded Applications
- •21.1 Chapter Overview
- •21.2 Introduction
- •21.3 Motivation for Multithreaded Programs
- •21.4 Fundamentals of Multithreaded Servers
- •21.5 Multithreading Strategies
- •21.6 Implementing a Multithreaded Server
- •21.7 Servant Activators and the Evictor Pattern
- •21.8 Summary
- •22.1 Chapter Overview
- •22.2 Introduction
- •22.3 Reducing Messaging Overhead
- •22.4 Optimizing Server Implementations
- •22.5 Federating Services
- •22.6 Improving Physical Design
- •22.7 Summary
- •Appendix A. Source Code for the ICP Simulator
- •Appendix B. CORBA Resources
- •Bibliography
IT-SC book: Advanced CORBA® Programming with C++
reference counting easier for clients, but that solution only makes mistakes less likely instead of preventing them.
The additional calls over the network for the increment and decrement operations may generate more network traffic than we can tolerate, at least for short-lived objects.
12.7.10 Summary of Options
As the discussion shows, there are no easy solutions for garbage collection. The most promising approach is the Evictor pattern, which is easy to implement and effective in many situations. All the remaining options are difficult to implement, intrusive, proprietary, or error-prone and so are unlikely to be worth pursuing.
We could attempt to remedy some of the problems described here with additional effort or by combining various techniques. For example, in a distributed reference counting approach, we could use one of the ping techniques to adjust reference counts that are left too high by crashed clients. However, that brings us to the most serious drawback: it simply is not reasonable for application developers to invent grand garbage collection schemes for their applications. Not only is the effort required far too high, but also the different schemes would most likely be incompatible, and application developers would find themselves in a maze of incomprehensible garbage collection requirements.
For garbage collection to work in a practical manner, it must be provided by the platform. The OMG has taken initial steps to add garbage collection to CORBA [23]. However, it is likely that several more years will pass before we will see garbage collection as a platform feature. Until then, the Evictor pattern will have to do.
12.8 Garbage Collection of CORBA Objects
So far, we have considered garbage collection only of transient servants for transient references. This arrangement simplifies the problem considerably because, in this case, the servant and the CORBA object are almost always the same thing; they are both created at the same time and destroyed at the same time, and using servant managers for transient objects is somewhat unusual. When we consider persistent CORBA objects, however, it becomes difficult even to decide what garbage collection should mean, let alone how to implement it.
Consider a persistent CORBA object representing a person. The object could keep a record of personal details in a database. Clearly, person objects have long life cycles, typically measured in decades. If we want garbage collection for CORBA objects, we must decide what garbage collection actually means. In particular, if we have a servant representing a person object in memory and decide to garbage-collect the servant, the question arises whether destroying the servant should also destroy the persistent database record of the person. For persons, the answer is most likely "no." The fact that the servant is destroyed does not necessarily mean that the persistent record, which represents the
523
IT-SC book: Advanced CORBA® Programming with C++
CORBA object, should also be destroyed. After all, the fact that we have reclaimed a servant to free some memory does not mean that the corresponding person has died.
Looking at objects with a shorter life span, it becomes more difficult to make a clear-cut decision about whether to destroy only the servant or both it and the CORBA object. For example, we may have document objects that represent documents in an archive. Typically, when clients "lose interest" in a document, we want to reclaim the servant for a document object but retain the persistent state of the document. For example, the attention span of most people for doing their taxes is quite short. However, the tax office has a much longer attention span and may well develop interest in a particular document some years after the last client has used it. On the other hand, sooner or later, the statute of limitations expires and we want to garbage-collect not only the servant for the document but also its persistent state. To make matters worse, when the time has come to destroy the document, there may be no servant in existence to remind us that it is time to destroy it.
The preceding examples show that the meaning of garbage collection is highly dependent on each application's requirements. In some cases, to garbage-collect an object means to reap its servant. In other cases, both servant and persistent state must be destroyed, and in yet still others, the circumstances change over time.
12.8.1 The Pacific Ocean Problem
Let us make a simplifying assumption for a moment by stating that to garbage-collect a CORBA object always means to destroy both the servant (if one exists) and the persistent state for the object. What we would like then is that no explicit call to destroy be necessary to make an object disappear. Instead, we would like the object to hang around for as long as clients are interested in it and to automatically disappear after the last client loses interest. Unfortunately, it is generally impossible to know when that time has arrived.
Consider the following scenario: You are stranded on an island in the Pacific Ocean, with a CORBA server as your only link to the rest of the world (you can reply to CORBA messages, but you cannot send them). Being desperate to get home, you decide to create a persistent SOS object in your CORBA server. You write the stringified IOR for your object on a piece of paper, put it into a bottle, and, having carefully inserted the cork, you toss the bottle into the ocean.
The bottle floats around for a few months and eventually washes ashore in Australia, where it is found by someone strolling along the beach. Luckily, the finder of your bottle knows all about CORBA, de-stringifies the object reference, contacts your object to learn about your predicament, and comes to the rescue.
Contrived as this example is, it illustrates an important point: because CORBA permits persistent references to propagate by uncontrollable means, there is no way of knowing whether or not an IOR is still of interest to some client. In the preceding scenario, the
524
IT-SC book: Advanced CORBA® Programming with C++
IOR continues to be of interest while it is floating in the Pacific Ocean, and the finder of the bottle has every right to expect a CORBA invocation via the IOR to reach your SOS object.
Of course, we do not normally store object references in the Pacific Ocean. However, an equivalent action is to write a stringified reference into a file, to send a stringified reference in an e-mail message, or to bind a reference in the Naming Service (see Chapter 18). The semantics of persistent references make it impossible to safely garbage-collect an object. We could decide to destroy an object at any time without warning, but that might leave a client with a dangling reference. The next time that client used the reference, it would get an OBJECT_NOT_EXIST exception.
12.8.2 Referential Integrity
Dangling references fall under the broader topic of referential integrity. A system of CORBA objects and their IORs has referential integrity if there are no dangling references (references without objects) and there are no orphaned objects (objects that cannot be contacted via a reference). As an analogy, the Web would exhibit referential integrity if there were no broken links and if every page could be reached from some starting point by traversing some sequence of links. Clearly, it is difficult to maintain referential integrity in a heterogeneous distributed system that spans enterprise and administrative boundaries; random failures that compromise referential integrity are unavoidable.
One way to deal with lack of referential integrity is to live without it. In real life, we cope with lack of referential integrity all the time. For example, when people dial a telephone number and get a "no such number" message (the equivalent of a dangling reference), they do not throw up their hands in despair. Instead, they have a number of fallback behaviors to recover from the problem (such as using the phone book or calling directory assistance).
In CORBA, the equivalent fallback behavior is not to rely on references to work at all times but to dynamically reacquire them when they fail. However, the effort required to implement such fallback behavior is prohibitive for applications. For example, both transactions and garbage collection can be effectively used to guarantee referential integrity and to provide fallback behavior in a system. But unless such features are provided by the underlying platform, they might as well not exist.
12.8.3 The Future of Garbage Collection
This section has raised more questions than it has answered. The problem of distributed garbage collection is largely unsolved and belongs firmly in the research area, at least for general-purpose object models such as CORBA's. The point of this discussion is to illustrate the deep issues we encounter when we start to consider what it means to destroy a servant or a CORBA object and how we would decide which to destroy. We also hope that we have shown enough about these problems to make you wary if a member of your
525
IT-SC book: Advanced CORBA® Programming with C++
next project suggests that you "just implement a simple garbage collector." Unless you can define precisely how such a collector would work, you should hold any such suggestion firmly at arm's length.
12.9 Summary
This chapter presents approaches to managing the life cycle of objects. The OMG Life Cycle Service offers one possible approach, but because of the problems associated with this service, you may be better off creating non-standard interfaces that preserve type safety. The Evictor pattern offers a simple and effective way to limit memory consumption in servers, and that is the key to creating servers that scale to large numbers of objects. In addition, the Evictor pattern provides an effective and transparent way to garbage-collect your servants. The more general topic of garbage collection of CORBA objects is largely unsolved because it is difficult to reconcile with the CORBA object model as well as application semantics.
526
