Transcript Chapter 17
Lecture 15
Object oriented databases
Object Definition Language (ODL)
module DreamHome
Class Branch
(extent branchOffices key branchNo)
{
attribute string branchNo;
….
relationship Manager ManagedBy
inverse Manager::Manages;
void takeOnPropertyForRent(in string propertyNo)
raises(propertyAlreadyForRent);
}
2
Object Definition Language (ODL)
class Person {
attribute struct Pname {string fName, string lName}
name;
}
Class Staff extends Person
(extent staff
key staffNo)
{
attribute staffNo;
attribute date DOB;
….
short getAge();
}
3
Object Definition Language (ODL)
class Manager extends Staff
(extent managers)
{
relationship Branch Manages
inverse Branch::ManagedBy;
}
4
Object Query Language (OQL)
Provides declarative access to object database
using SQL-like syntax.
Does not provide explicit update operators leaves this to operations defined on object
types.
Can be used as a standalone language and as
a language embedded in another language,
for which an ODMG binding is defined
(Smalltalk, C++, and Java).
OQL can also invoke operations programmed in
these languages.
5
Object Query Language (OQL)
Can be used for
navigational access:
associative
and
• Associative query returns collection of objects. How
these objects are located is responsibility of ODMS.
• Navigational query accesses individual objects and
object relationships used to navigate from one object
to another. Responsibility of application program to
specify procedure for accessing the objects.
6
Object Query Language (OQL)
An OQL query is a function that delivers an object
whose type may be inferred from operator
contributing to query expression.
Query definition expressions is of form:
DEFINE Q as e
Defines query
expression e.
7
with
name
Q
given
query
Object Query Language (OQL)
Expression can take several forms:
•
•
•
•
Elementary
Atomic type
Collection
Binary set
- Construction
- Object
- Indexed collections
- Conversion
Query consists of a (possibly empty) set of query
definition expressions followed by an
expression.
Result is object with or without identity.
8
Example 28.2 OQL: Extents & Traversal Paths
Get set of all staff (with identity)
staff
Get set of all branch managers (with identity)
branchOffices.ManagedBy
9
Example 28.2 OQL: Extents & Traversal Paths
Find all branches in London
SELECT b.branchNo
FROM b IN branchOffices
WHERE b.address.city = “London”;
This returns a literal of type bag<string>.
10
Example 28.2 OQL: Extents & Traversal Paths
Assume londonBranches is named object (from
last query). Find all staff who work at that
branch.
londonBranches.Has
This returns set<SalesStaff>.
11
Example 28.2 OQL: Extents & Traversal Paths
Because of ambiguity over return result, cannot
access sales staff salaries using:
londonBranches.Has.salary
Result may be set<float> or bag<float>.
Instead use:
SELECT [DISTINCT] s.salary
FROM s IN londonBranches.Has;
12
Example 28.3 - OQL: Use of DEFINE
Get set of all staff who work in London (without
identity).
DEFINE Londoners AS
SELECT s
FROM s IN salesStaff
WHERE s.WorksAt.address.city = “London”;
SELECT s.name.lName FROM s IN Londoners;
This returns a literal of type set<string>.
13
Example 28.3 - OQL: Use of DEFINE
Can generalize this:
DEFINE CityWorker(cityname) AS
SELECT s
FROM s IN salesStaff
WHERE s.WorksAt.address.city = cityname;
CityWorker(“London”);
CityWorker(“Glasgow”);
14
Example 28.4 OQL: Use of structures
Get structured set (without identity) containing
name, sex, and age of all staff who live in
London.
SELECT struct (lName:s.name.lName, sex:s.sex,
age:s.age)
FROM s IN Staff
WHERE s.WorksAt.address.city = “London”
This returns a literal of type set<struct>.
15
Example 28.4 OQL: Use of structures
Get structured set (with identity) with name, sex,
and age of all deputy managers over 60:
class Deputy {attribute string lName; attribute
sexType sex; attribute integer age;};
Typedef bag<Deputy>Deputies;
Deputies (SELECT Deputy (lName:s.name.lName,
sex:s.sex, age:x.age)
FROM s IN salesStaff
WHERE position = “Deputy” AND s.getAge >
60)
This returns a mutable object of type deputies.
16
Example 28.4 OQL: Use of structures
Get structured set (without identity) containing
branch number and set of all Assistants at
branches in London.
SELECT struct (branchNo:x.branchNo, assistants:
(SELECT y FROM y IN x.WorksAt
WHERE y.position = “Assistant”))
FROM x IN (SELECT b FROM b IN branchOffices
WHERE b.address.city = “London”)
This returns a literal of type set<struct>.
17
Example 28.5 OQL: Use of aggregates
How many staff work in Glasgow.
COUNT (s IN CityWorker(“Glasgow”);
OQL aggregate can be applied within SELECT or
to result of SELECT.
Following equivalent:
SELECT COUNT(s) FROM s IN salesStaff
WHERE s.WorksAt.branchNo = “B003”;
COUNT(SELECT s FROM s IN salesStaff
WHERE s.WorksAt.branchNo = “B003”);
18
Example 28.6 OQL: GROUP BY
Determine number of sales staff at each branch.
SELECT struct(branchNumber,
numberOfStaff:COUNT(partition))
FROM s IN salesStaff
GROUP BY branchNumber: s.WorksAt.branchNo;
Result is of type: set<struct(branchNumber: string,
partition: bag<struct(s:SalesStaff)>)>
Note use of keyword partition to refer to each
partition.
19
OQL - Creating Objects
A type name constructor is used to create an
object with identity.
Manager(staffNo: “SL21”,
fName: “John”, lName: “White”,
address: “19 Taylor St, London”,
position: “Manager”, sex: “M”,
DOB: date“1945-10-01”, salary: 30000)
20
Language Bindings
Specify how ODL/OML constructs are mapped
to programming language constructs.
Basic design principle is that programmer
should think there is only one language being
used.
C++ class library provided containing classes
and functions that implement ODL constructs.
Also, OML is used to specify how database
objects are retrieved and manipulated within
application program.
21
Language Bindings - Creating a Working Application
22
Language Bindings
Features that implement interface are prefixed
d_ (e.g. d_Float, d_String, d_List, d_Set, and
d_Bag).
Also class d_Iterator a class d_Extent.
Template class d_Ref(T) defined for each class
T in database schema that can refer to both
persistent and transient objects of class T.
23
Language Bindings
Relationships handled by including either a
reference (for 1:1) or a collection (for 1:*). For
example, to represent 1:* Has relationship in
Branch class:
d_Rel_Set<SalesStaff, _WorksAt> Has;
const char _WorksAt[] = “WorksAt”;
and to represent same relationship in SalesStaff
class:
d_Rel_Ref<Branch, _Has> WorksAt;
const char _Has[] = “Has”;
24
Language Bindings - OML
new operator overloaded so that it can create
persistent or transient objects.
To create a persistent object, a database name
and a name for the object must be provided.
For example, to create a transient object:
d_Ref<SalesStaff>
SalesStaff;
tempSalesStaff
=
new
new(myDb,
“John
and to create a persistent object:
d_Database *myDB;
d_Ref<SalesStaff> s1
White”) SalesStaff;
25
=
Language Bindings - OQL
OQL queries can be executed from within C++
in one of following ways:
• using query member function of the d_Collection
class;
• using d_OQL_Query interface.
d_Bag<d_Ref<SalesStaff>> wellPaidStaff;
SaleStaff->query(wellPaidStaff,
“salary
30000”);
d_OQL_Query q(“SELECT s.WorksAt
FROM s IN SalesStaff WHERE salary > $1”);
d_Bag<d_Ref<Branch>> branches;
q << 30000;
d_oql_execute(q, branches);
26
>
Mapping Conceptual Design to Logical OO
Design
Step 1 Mapping classes
• Map each class or subclass to an ODL class,
including all appropriate attributes and methods.
• Map composite attributes to a tuple constructor using
a struct declaration.
• Map any multivalued attributes as follows:
–
–
–
if values are ordered, map to a list constructor;
if values contain duplicates, map to a bag constructor;
otherwise, map to a set constructor.
Create an extent for each class that will be iterated
over. Specify EXTENDS for each ODL class that
represents a subclass to inherit attributes and
methods of superclass.
27
Mapping Conceptual Design to Logical OO
Design
Step 2 Mapping binary relationships
• Add a relationship property (or reference attribute)
into each class that participates in relationship.
• If supported, use inverse relationships where possible
to ensure system automatically maintains RI;
otherwise program this functionality into class
methods.
• If 1:1, each relationship property will be single-valued.
• If 1:*, relationship property will be single-valued on
one side and collection type (list or set) on the other.
• If *:*, each side will be a collection type.
• Create tuple constructor (struct) for relationships
attributes of form <relationship reference, relationship
attributes>.
28
Mapping Conceptual Design to Logical OO
Design
Step 3 Mapping n-ary relationships
• For each relationship with degree greater than 2,
create separate class to represent relationship and
include relationship property (based on a 1:*
relationship) to each participating class.
Step 4 Mapping categories
• For each category (union type), create class to
represent category and define a 1:1 relationship
between category class and each of its superclasses.
• Alternatively, a union type can be used if OODBMS
supports it.
29
ObjectStore - Architecture
Based on multi-client/multi-server architecture,
with each server responsible for controlling
access to an object store and for managing
concurrency control (locking-based), data
recovery, and transaction log, among others.
A client can contact ObjectStore server on its
host or any other ObjectStore server on any
other host in network.
30
ObjectStore - Architecture
For each host machine running one or more
clients there is an associated cache manager
process to facilitate concurrent access to data
by handling callback messages from server to
clients.
Also, each client has its own client cache, which
acts as a holding area for data mapped (or
waiting to be mapped) into physical memory.
31
ObjectStore Architecture
32
ObjectStore Server
Responsible for:
• storage and retrieval of persistent data;
• handling concurrent access by multiple client
applications;
• database recovery.
33
Client Application
Objectstore client library is linked into each
client application, allowing it to:
• map persistent objects to virtual addresses;
• allocate and deallocate storage for persistent
objects;
• maintain a cache of recently used pages and the
lock status of those pages;
• handle page faults on addresses that refer to
persistent objects.
34
Client Cache
Exists to improve access to persistent objects.
When client application needs to access a
persistent object, then a page fault is
generated when:
• object is not in physical memory and not in client
cache;
• object is in client cache but has not yet been
accessed;
• object is in client cache but has been previously
accessed with different read/write permissions.
35
Virtual Memory Mapping Architecture (VMMA)
C++ object is stored in database in its native
format with all pointers intact (unswizzled).
Basic idea of VMMA is same as for virtual
memory management in operating systems.
References to objects are realized by virtual
memory addresses. If object has to be
dereferenced and the page object resides on is
in memory, there is no extra overhead in
dereferencing this object (dereferencing is as
fast as for any C/C++ program).
36
Virtual Memory Mapping Architecture (VMMA)
If required page not in memory, page fault
occurs and page is brought into same virtual
memory address it originally occupied.
Thus, pointers to this object in other transferred
objects are valid virtual memory pointers
referring to their original target.
Unmapped range of virtual memory reserved for
persistent objects, thereby ensuring that this
range will be used for no other purpose than
database pages.
37
Building an ObjectStore Application
38
ObjectStore Databases
ObjectStore supports two types of databases:
• file database, a native operating system file that
contains an ObjectStore database;
• rawfs (raw file system) database, a private file system
managed by the ObjectStore server, independent of
file system managed by operating system.
Database divided into clusters and segments. A
cluster is basic unit of storage allocation. When
a persistent object is created storage is
allocated from a cluster. Clusters are divided
into segments.
39
Data Definition in ObjectStore
Can handle persistence for objects created in
C/C++ and Java through separate class
libraries, and objects created in one language
can be accessed in other.
For C++, ObjectStore uses C++ as a schema
language so that everything in database must
be defined by C++ class.
Persistence is orthogonal to type and persistent
object support achieved through overloading
new operator.
branchNo = new(DHomeDB, os_typespec::get_char(), 4) char[4];
40
Data Definition in ObjectStore
Also a version of C++ delete operator to delete
persistent objects and free persistent memory.
Once persistent memory has been allocated,
pointers to this memory can be used in same
way as pointers to virtual memory.
41
Creating Relationships in ObjectStore
Relationship between Branch and SalesStaff
handled by declaring two data members that are
inverses of each other.
RI automatically maintained.
Macros provided for defining relationships:
os_relationship_1_1; os_relationship_m_m;
os_relationship_1_m; os_relationship_m_1.
os_relationship_1_m(SalesStaff, WorksAt, Branch, Has, Branch*)
WorksAt;
os_relationship_m_1(Branch,
Has,
SalesStaff,
WorksAt,
os_Set<SalesStaff*>) Has;
42
Data Manipulation in ObjectStore
Following operations must be performed before
persistent memory can be accessed:
• a database must be created or opened;
• a transaction must be started;
• a database root must be retrieved or created.
43
Roots and Entry Point Objects
Database root provides way to give an object a
persistent name, thereby allowing object to
serve as entry point into the database.
From there, any object related to it can be
retrieved using navigation (i.e., following data
member pointers) or by a query (i.e., selecting
all elements of a given collection that satisfy a
specified predicate).
44
Roots and Entry Point Objects
45
Access Based on a Named Root
aBranch = (Branch*)(db1->find_root(“Branch3_Root”)
->get_value(WorksAtType);
cout << “Retrieval of branch B003 root: ” <<
aBranch->branchNo << “\n”;
46
Iteration of Collections using Cursors
os_Cursor<SalesStaff*> c(aBranch->Has);
cout << “Staff associated with B003: \n”
for (p = c.first(); c.more(); p = c.next())
cout << p->staffNo << “\n”;
47
Lookup of Single Object Based on Value of one or more
Data Members
salesStaffExtent = (os_Set<SalesStaff*>*)
(db1->find_root(“salesStaffExtent_Root”)
->get_value(salesStaffExtentType);
aSalesPerson = salesStaffExtent
->query_pick(“SalesStaff*”,“!strcmp(staffNo,\“SG37\”)”,
db1);
cout << “Retrieval of specific member of sales staff: ” <<
aSalesPerson.staffNo << “\n”;
48
Lookup of Single Object Based on Value of one or more
Data Members
os_Set<SalesStaff*> &highlyPaidStaff =
salesStaffExtent->query(“SalesStaff*”,
“salary > 30000”, db1);
cout << “Retrieval of highly paid staff: \n”;
os_Cursor<SalesStaff*> c(highlyPaidStaff);
for (p = c.first(); c.more(); p = c.next())
cout << p->staffNo << “\n”;
49