*start*
00370 00024 US 
Date: 16 Sept. 1981 4:05 pm PDT (Wednesday)
From: kolling.PA
Subject: FS note
To: taft, mbrown
cc: kolling

FS may wish to complain if its client hands it more than one request for the
same property in Read/WriteProperties.  AC's interface is being changed so that it
can't be fed duplicate lists in the same operation, so it will not see this.

*start*
00631 00024 US 
Date: 16 Sept. 1981 6:29 pm PDT (Wednesday)
From: Taft.PA
Subject: Alpine Grapevine
To: Birrell
cc: Schroeder, MBrown, Kolling, Taft

I have snatched copies of the Grapevine interfaces that were developed for the
Walnut project by Robert Nix, and I have stored them on
[Ivy]<Alpine>Defs>Grapevine>*.  I had to recompile the defs files because the
Rope interface has changed since they were last recompiled.

Also in the same subdirectory is an updated (Cedar-style) version of my
speculative GVAuthenticate interface.

Grapevine.df brings over all these Grapevine interfaces, including
GVAuthenticate.
	Ed

*start*
01991 00024 US 
Date: 17 Sept. 1981 5:21 pm PDT (Thursday)
From: Nelson.PA
Subject: Alpine interfaces and RPC
To: Taft, MBrown, Kolling
cc: Birrell, Boggs, Nelson

I read through your very good design documents, and have these RPC-related
comments.

The names of the three stub modules (and files, with .mesa) are (for example):

	AlpineAccessRpcControl
		(the binding interface)
	AlpineAccessRpcClientImpl
		(imports RPC ; exports AlpineAccess, AlpineAccessRpcControl) 
	AlpineAccessRpcServerImpl
		(imports RPC, AlpineAccess; exports AlpineAccessRpcControl)

The latter two are bound into your configurations along with RpcRuntime.

It is quite likely that the encryption-related definitions will move to a new,
public, non-Rpc-specific interface(s).  The intent is that the RPC interface be
strictly private to Lupine and the stubs.  Plus, the encryption stuff will probably
have a broad community.  (In light of this change, XXRpcControl may change to
XXRpcBinding; not clear yet; probably not.)

Your msg was fortunately timed in that I was preparing a marshaling memo at
the same time.  Your use of Ropes and REF ANY caused some changes in my
thinking.  I now propose to marshal ropes (perhaps expensively), but there's no
chance for REF ANY.  However, a variant record for properties might do if you
are willing to map between REFs and variants at remote boundaries.

VALUE and RESULT must appear in the type names, as the upcoming memo
describes.

It is not difficult to handle address-containing types at levels>1. Diplomat does
this.  But there is a specification problem (which Diplomat handles poorly):  is
the parameter flavor always VALUE, always RESULT, inherited, or what? 
Programmers using pointers to get VAR parameters want dereferencing; those
using pointers as handles do not.  Lupine can probably get standard idioms right
98% of the time, but what about other cases?

The marshaling memo will explore the last three issues, and more, further. 

						Bruce
*start*
02806 00024 US 
Date: 18 Sept. 1981 3:58 pm PDT (Friday)
From: Taft.PA
Subject: FYI: multi-pack logical volumes
To: MBrown, Kolling

As I was saying......

---------------------------

Date: 18 Sept. 1981 3:08 pm PDT (Friday)
From: PSmith.ES
Subject: IFS Questions
To: Taft.pa
cc: PSmith

Ed,

I have two questions that I would like to ask your advice on:

.....

2.) Second question:  We have been unsuccessful in "Brownieing" from
[Ivy]<Dover>Clover>Spruce.fonts due to transcient errors.  The Spruce.fonts file is
13726 pages in total.  We were sucessful in FTP'ing the file Spruce.fonts from up
north to a T-80.  This T-80 is not a file server, so in order to get the Spruce.fonts
file onto our IFS, ISIS we tried to FTP the file Spruce.fonts from the T-80 to Isis. 
We were not successful we encountered the error message: "disk full"  I checked
the Dover directory on Isis and it had 14000 available pages, the spruce.fonts file
is 13726 pages in length.  My question, why couldn't we successfully FTP from
the T-80 to the IFS?  As a side note we were successful in FTPing the file
Spruce.fonts from the T-80 to our printers T-80.  Have you ever encountered this
kind of a problem with FTP in the past?

Thank-you for your time,
Patty Smith  823-9272

---------------------------

Date: 18 Sept. 1981 3:53 pm PDT (Friday)
From: Taft.PA
Subject: Re: IFS Questions
In-reply-to: Your message of 18 Sept. 1981 3:08 pm PDT (Friday)
To: PSmith.ES
cc: Taft

......

2. The file system is divided into multiple "logical units" for software reasons;
there are two logical units (about 65,000 pages each) on each T-300 disk.  Each
individual file has to be entirely contained on a single logical unit. 
Consequently, you can't store a file larger than the amount of free space on the
emptiest logical unit.  (The Statistics command shows the amount of free space on
each logical unit.)

This causes problems when you are trying to store a very large file on a large
IFS that is nearly full, since the remaining free space will tend to be
more-or-less evenly divided between the logical units, and so any individual
unit will have a relatively small amount of space.

The way we deal with Spruce.fonts is to store new copies on top of the existing
one, rather than creating a new version as is ordinarily done.  That is, if you
already have a <Dover>Clover>Spruce.fonts!1, then store on top of that exact file
rather than creating <Dover>Clover>Spruce.fonts!2.

If you don't already have a Spruce.fonts of approximately the right size, then I'm
afraid you are out of luck for now.  Next time you add another T-300 pack to the
system, you should quickly store Spruce.fonts so as to "reserve" the necessary
space all on one logical unit.
	Ed

------------------------------------------------------------

*start*
02780 00024 US 
Date: 18 Sept. 1981 5:50 pm PDT (Friday)
From: Taft.PA
Subject: Internal use of FileStore interfaces
To: MBrown, Kolling
cc: Taft

I've developed the following model of how internal clients (such as the
AccessControl implementation) should make use of the public FileStore
interfaces.  Please tell me if you see anything wrong with it, as it's fairly
fundamental.

1. Internal clients will bind directly to the public interfaces.  That is, the public
interfaces won't be a veneer over some corresponding local interfaces; rather,
internal clients such as AccessControl will directly call AlpineFile, etc.  This is
NOT the same as saying that internal calls to the public interfaces will use RPC. 
However, it DOES mean that internal and remote calls through the FileStore
interfaces will be indistinguishable from the FileStore implementation's point of
view.  In particular, it means that most internal calls through FileStore must pass
a ConnectionID just the same as a remote client.

2. When an internal client is performing work on behalf of some external client,
the internal client will pass the ConnectionID corresponding to that external
client when calling the public FileStore interfaces.

3. When an internal client is performing work on its own behalf (e.g.,
AccessControl operating on the owner data base file), it will pass a special
ConnectionID which corresponds to that internal client.  This ConnectionID is
created at initialization time and remains constant thereafter.

The consequence of (2) on our present system organization is that we must use a
ConnectionID in many places where we now use a ClientName (or ClientID, as
we used to call it).  For example, all the AccessControl procedures that are passed
a ClientName to identify the calling client, such as AddOwner and
CheckAccessFile, should instead be passed a ConnectionID.  This is so that the
implementation can in turn pass the same ConnectionID to FileStore when
performing file operations on behalf of the client rather than on its own behalf.

When the actual ClientName (RName) is required, it is possible to obtain it from
the ConnectionID.  I intend to provide a ConnectionMap that efficiently maps
from ConnectionID to ClientName; it will be maintained by FileStore using
information provided by AlpineAccess.Login and Logout.

If we adopt this approach, the use of ConnectionIDs within Alpine is likely to
become quite widespread, and to pervade to regions of the system that wouldn't
otherwise think in terms of RPC, connections, etc.  So I propose to rename
ConnectionID to be ClientHandle.  A ClientHandle represents an authenticated
client on behalf of which some operation is to be performed; that client may be
either external or internal to FileStore.
	Ed

*start*
02711 00024 US 
Date: 20 Sept. 1981 9:44 am PDT (Sunday)
From: Taft.PA
Subject: RPC type safety
To: Nelson, Birrell, Boggs
cc: MBrown, Kolling, Taft

I'm now convinced that the RPC conversation encryption mechanisms will
guarantee the authenticity of clients.  However, if we aren't careful, an
authenticated client can still bring the server to its knees by violating the type
system.  I assume the RPC design group has considered this problem.  Here are
my thoughts.

The Cedar safe language ensures only that address-containing types will not be
confused with each other or with random bit patterns.  From Cedar's point of
view, confusing two non-AC types doesn't endanger the Cedar runtime system,
so Cedar doesn't enforce type-correctness in such a case.  Since AC types are not
passed across remote interfaces (they are always dereferenced and passed by
value), I conclude that the Cedar safe language does not buy us any guarantees
of type safety.  (This is probably just as well, since such guarantees would be
hard to enforce remotely in any event.)

The first problem is that a client may use LOOPHOLEs to pass arbitrary garbage
as arguments to a procedure call.  There's nothing RPC can do about this.  This
means that implementations must be somewhat cautious about the
type-correctness of their arguments.  For example, a value of an enumerated type
or subrange may be out of bounds; an array may be larger than was declared in
the type; etc.  It may be worth attempting to draw up an exhaustive list of
things that the server must check for.

[Note to Alpine implementors: whatever checking is required will be performed
by FileStore, right at the level of the exported interface.  Implementations of
internal interfaces may assume type-correctness of their arguments.  Also,
internal calls to a FileStore, either local or remote, may be considered type-safe:
RPC guarantees that the remote FileStore is authentic, and FileStores are assumed
to be cooperative rather than hostile.]

The second problem is that a client may cause runtime errors in the server.  The
only one I can think of at the moment is a stack error caused by a mismatch in
the number or size of arguments to a procedure.  This can happen if, at remote
binding time, the client lies to RPC about what interface it is importing.  I'm
hoping that RPC can make some guarantees about this, since it's at a level that is
invisible to the implementation.  At least, any runtime errors that occur should
occur within the RPC machinery (not within the implementation) and either be
reflected back to the client or be reported to the implementation in a controlled
way.

Are there any other issues or problems of this sort?
	Ed

*start*
00871 00024 US 
Date: 20 Sept. 1981 10:34 am PDT (Sunday)
From: Taft.PA
Subject: ConversationID generation
To: Birrell, Nelson, Boggs
cc: MBrown, Kolling, Taft

We are using RPC ConversationIDs to identify the client of an interface.  There
will be situations in which a client is local rather than remote and binds directly
to the interface rather than using RPC.  For uniformity, we will need a
ConversationID to identify that client as well, even though RPC is never
involved in the conversation.

Therefore, I would like to be able to ask RPC to generate a unique ConnectionID
for my own use, not associated with a conversation key or with an actual RPC
conversation.  I am adding a procedure GenerateConversationID to my speculative
version of the RPC interface, [Ivy]<Alpine>Defs>RPC.mesa.  If there are any
difficulties with this, please let me know.
	Ed

*start*
01121 00024 US 
Date: 21 Sept. 1981 9:55 am PDT (Monday)
From: Nelson.PA
Subject: Re: ConversationID generation
To: Taft.PA
cc: Birrell, MBrown, Kolling, Nelson

I am slightly confused because you used "ConnectionID" once in your message. 
If what you want is a way to generate conversationIDs directly, I believe you
will have no problem.  The Authenticate (or somesuch) interface will have the
procedure you want (remember, Andrew is going to separate all this security
stuff from RPC.mesa).  I, in fact, believe that you will always generate these
IDs, just using our procedure so that they have a nice form for us.  Once in
your hands, you pass them back to us as necessary.

Also, Andrew proposes that the ConversationID argument be restricted to be the
first one in any argument list.  In the absence of dissention, Lupine will
implement this.

FInally, using ConversationIDs to identify the clients of an interface seems like
an excellent thing to do, along the lines of my embedded-handle idea.  Of
course, of a superior binding scheme appears, this decision might stand some
reevaluation.

					Bruce

*start*
02749 00024 US 
Date: 21 Sept. 1981 10:39 am PDT (Monday)
From: Nelson.PA
Subject: Re: RPC type safety
To: Taft.PA
cc: Nelson, Birrell, Boggs, MBrown, Kolling

Type Safety.

While your memo enumerates some real problems, my first thought was that
nearly all the problems are also present in the local case--LOOPHOLES, bounds
checks, and so forth.  Even if clients program in the safe language, can't they
declare themselves to be CHECKED or somesuch and then get away with
whatever they want?  Thus the problems are with general type safety, not RPC
type safety in particular.

Runtime Errors.

I agree that runtime errors can occur in the RPC system.  Stack errors, however,
will not happen because Lupine generates source text that performs standard
procedure calls.  Any misbehavior will be detected when the stubs are compiled. 
What can happen, however, is that the marshaling code receives parameter
records of the wrong size (because of misbinding, protocol errors, client malice). 
This is Lupine's version of stack error.   Right now, I believe most of these errors
will happen in the client stub as the (for instance) bogus descriptor is marshaled
for the outward trip.

All these specific details aside, in a short msg to Andrew last week I outlined the
three kinds of runtime ERRORs Lupine is likely to detect and cause the stubs to
raise:

LupineBindingError:  eg, calling Export on a client, Import on server.
LupineRuntimeError:  eg, ENDCASE => LupineRuntimeError.
LupineMarshalError:  as above; perhaps this could flush one call only.

At the time I thought that these were unrecoverable and would land in the
debugger (of the raising host only).  Perhaps a better scheme is that the
RpcRuntime catches them (server only) and calls a special procedure you register
at Export time.  This gives you control over restarting, booting, or whatever. 
Hmm...I guess a backstop normally does this, and somewhat better.

Interface Consistency.

One prolific source of errors will be the "version" field of an InterfaceName. 
Mesa's conservative approach to interface consistency causes headaches, but it 
also provides an ironclad guarantee.  Diplomat's philosophy was to extend this
uniformly:  Diplomat would not bind two parties unless their compiled-in Mesa
versionstampes agreed at runtime.  We know this is not suitable for large,
evolving systems, and thus RPC clients get to call their own shots with
"version."  Many will erringly shoot themselves down.  Lupine's contributing
arrows will be the RuntimeError (undefined procedure called) and the
MarshalError (wrong procedure called).


Finally, I believe that other problems of this flavor will arise.  But I usually
don't find them until I'm writing the code.

						Bruce
*start*
12257 00024 US 
Date: 21 Sept. 1981 1:36 pm PDT (Monday)
From: Nelson.PA
Subject: A Preliminary Position on Lupine's Parameter Marshaling
To: MBrown, Taft, Kolling
To: Satterthwaite, Rovner, Levin, Swinehart, Atkinson 
cc: Birrell, Nelson


RPC friends:

Lupine (pronounced loo-pin) is Cedar's RPC stub translator.  To its human users
and RPC-using client programs, Lupine closely resembles Diplomat.  Internally,
however, Lupine generates stubs which
	[1] contain inline marshaling code and
	[2] call a special RPC runtime system that provides
	    secure (authenticated, encrypted) RPC packet transport and
	    a Grapevine-oriented remote binding scheme.
This Liaison-derived design, which eliminates high-level intermediaries such as
Courier, is motivated by a strong performance goal.  Client- and server-level
syntactic and semantic transparency is not greatly sacrificed.


Progress Report

I'm happy to report that Lupine, which is far from complete, has successfully
generated the simple XxxRPCControl modules for a number of Xxx test interfaces. 
Some included Cedar-specific types.  This represents significant progress because
all the underlying code runs, and using Cedar/Tajo at that.


Marshaling

Now, to the heart of this missive.  Lupine's basic symbol table interface is now at
a point where I can begin writing the higher-level marshalling interface.  (To
"marshal" parameters is to move them back and forth between RPC packets and
parameter records.  The high-density connotation of "packing" is often wrong,
and "serialize" already has a poplular definition among the transaction folks.)


Type-specific Marshalings

Here are the Cedar types and how Lupine proposes to marshal them when they
occur as parameters.  It is the address-containing (AC) types that cause
difficulties.

Basic types--UNSPECIFIED, CHARACTER, BOOLEAN, REAL, INTEGER, ...,
subranges, and enumerations--are no problem.  They are sent intact, as you
would expect.

ARRAYs are no problem.  The elements are marshaled and sent.
ARRAY [0..0) OF ElementType--an old computed sequence idiom--will issue a
warning.  Doing PACKED arrays appears reasonable; we'll see.  (Computing the
size before Mesa6 provided SIZE[ElementType, #elements] was hard).

DESCRIPTORS are okay; the underlying arrays are marshaled and sent.

Nonvariant RECORDs are no problem as long as the component types are
marshalable. 

NonCOMPUTED variant RECORDs and SEQUENCEs are okay.  PACKED
sequences should be fine, as discussed above.  Computed variant records,
including OVERLAID, are illegal if they have address-containing types. 
Computed sequences are always illegal, although this is not strictly necessary for
sequences with bounds types of small cardinality.  Where possible, sequences
should have a reasonable upperbound specified.  Needlessly using a bounds
(index) type with a large cardinality--eg, NAT or CARDINAL, as in most string
types--can cause the slow multipacket machinery to be unnecessarily engaged. 
Again, sequences must have a marshalable element type.

POINTERs and REFs with statically marshalable nonrecursive referents are okay. 
The nonrecursive stipulation implies that Lupine will not infer the existence of
and marshal user-defined lists, trees, or graphs (see LIST, below).  POINTER (TO
UNSPECIFIED) is treated as a handle; i.e., just the uninterpreted pointer is sent. 
REF ANY is outright illegal; handling it requires a (costly) runtime marshaler,
and I expect writing the static one to take most of my time.  This is a task for
someone else down the road.

RELATIVE pointers and descriptors are not interpreted and are treated like the
basic types, with a warning.  Alternatively, they could be illegal.

STRING and TEXT (REF TEXT) are no problem.  For strings and (ref) text I
propose to always send the characters, not the pointers.

ROPEs are no problem, although they might be slow in the
non-STRING-equivalent case.  Lupine will recognize type Rope.Ref.

LONG versions of the above are okay.

Opaque TYPEs are handled as follows.  Assume the declaration T: TYPE.   For
the parameter p: REF --or (LONG) POINTER TO-- T, the pointer p will be sent. 
Alternatively, if T's length is known, send p↑ instead of p.  For a parameter t: T,
the entire object t will be sent iff the length is known (error otherwise).  

LISTs will be handled because of their utility.  They will be fairly expensive
because of the CONSes.  Order will be preserved.  Of course, if the target of a
list is unmarshalable, the list will be too.  For example, LIST OF TEXT is okay,
but LIST OF REF ANY is not.

ATOMs are questionable.  Marshaling atoms as unique print names is no
problem; property lists--for example, LIST OF RECORD [name: ATOM, prop: REF
ANY]--are out of the question.

PROCEDUREs (and probably SIGNALs and ERRORs, for what it's worth) are
permitted as arguments as well as interface items.  Client use of callback routines
must adhere to the stack discipline for now.  I propose to outlaw transfer-type
results until Cedar has closures.  The implementation of transfer parameters will
have low priority.

ZONEs are either illegal or treated as ZoneRep handles.  I believe handle is best
(see interMDS, below).



VAR, VALUE, RESULT, and HANDLE.

VAR, VALUE, and RESULT are supported through the typename-driven
mechanism derived earlier in the summer.  In the absence of aliasing, VAR is
identical to specifing both VALUE and RESULT.  For example:

	VALUEBuffer: TYPE =
			LONG DESCRIPTOR FOR READONLY ARRAY OF WORD;
	RESULTBuffer: TYPE =
			LONG DESCRIPTOR FOR ARRAY OF WORD;
	VALUERESULTBuffer: TYPE =
			LONG DESCRIPTOR FOR ARRAY OF WORD;
	VARBuffer: --same as VALUERESULTBuffer-- TYPE =
			LONG DESCRIPTOR FOR ARRAY OF WORD;

	GetPages: PROC [pages: Pages, buffer: RESULTBuffer];
	PutPages: PROC [pages: Pages, buffer: VALUEBuffer];

	XorBuffer: TYPE = VARBuffer;
	XorPages: PROC [pages: Pages, buffer: XorBuffer];

Simple example:

	Page: TYPE = ARRAY [0..Disk.PageSize) OF WORD;
	pageBuffers: ARRAY [0..*) OF Page;
	GetPages[ pages: [start, stop],
		    buffer: DESCRIPTOR[@pageBuffers, (stop-start)*SIZE[Page] ];

The underlying scheme is that VAR, VALUE, or RESULT can appear as
uppercase prefixes in the type names (possibly via some type definitions) of
top-level arguments.  These three attributes can be applied only to REFs,
POINTERs, LISTs, STRINGS, and DESCRIPTORs (or equivalent type definitions).

Default parameter attributes and consistency

There is uncertainty about the proper default treatment of address-containing
(AC) types.  My own preference is for value handling:  List, string, and
descriptor arguments are copied over but not back; results (i.e., return
parameters) of these same types are copied back.  For arguments, I realize this is
different semantics from Mesa, which gives VAR.  I could easily be talked into a
VAR default.  I just try to never do business that way myself.

[Aside:  For heap (nonGC) items such as string and descriptor bodies, there is a
deallocation problem.  A previously used solution is that the server stub frees
heap arguments before returning (it allocated them too); the client programmer
frees heap results himself (the client stub having allocated them).  Of course,
Cedar programmers are expected to use REF types and VALUE-RESULT to avoid
these problems entirely.]

For ropes, only value handling makes sense.  For refs and pointers, however, the
problem is harder.  My personal goal is to make Lupine do what is wanted 98%
of the time.  Andrew, however, is lobbying for absolute consistency.  For
example, I think his position is that if REF OpaqueType is treated as a handle,
all pointers (including STRING and REF TEXT) should be treated as handles. 
Programmers wanting dereferencing must always say (for example)
VALUESTRING.  Another example of this consistency question arises in the
suggested alternative handling of length-known opaque types (above).

I'm not a language designer and won't decide this question.  What I do know is
that [1] I prefer REF TEXT and STRING to send the characters by default (and
perhaps to bring them back); [2] if any AC type has nonhandle treatment, then
a way to force handle treatment is needed for completeness.  In this case, I
propose adding HANDLE to VAR, VALUE, and RESULT.

Your comments are solicited.  Observe that for string, ref text, list, and descriptor
types, default value(-result) treatment usually makes sense; it is the general ref
and pointer cases that are hard.  For example, consider the following as
parameters of a remote call:

	s: REF System.NetworkAddress;  -- Length known opaque type.
	c: LONG POINTER TO CARDINAL;
	r: REF FullName --RECORD [volume, directory, file: LONG STRING]--;

As a user programmer, I would want Lupine to send s↑ and r↑ because their
REFs are an underhanded statement of VALUE.   On the other hand, I would
not expect Lupine to figure out c.

Fortunately, it's unlikely that a sensible designer would include any of these
types in a real remote interface.  But that doesn't stop me from wanting to
consider the possibilities while there's still an even chance of doing something
about them.




Remote Interface Considerations

Interface transfers.  Lupine permits remote interfaces to contain resumable
SIGNALs as well as ERRORs and PROCEDUREs.  PROCESSes, PROGRAMs, and
PORTs are illegal; so is POINTER TO FRAME (which is actually an interface
variable, below).

Interface variables.  Interface variables are, of course, meaningless across
machine boundaries and therefore illegal in RPC interfaces.  Lupine gives a
translation-time warning and proceeds.  Notice the implications for inline
procedures.

Inline procedures.  Inline procedures are ignored by Lupine.  This means that
they expand at compile time in remote clients just as in local clients.  This is the
only treatment possible without changing the client's interface.  (Why would
you want to change a remote interface?  Assume that interface Defs has P: PROC
= INLINE {Defs.A[...]; Defs.B[...]; Defs.C[...]}, where A, B, and C are not inlines. 
When P is expanded in the client, a call of P results in three remote calls to the
server.  If P were not an inline, only one remote call would occur.)   


InterMDS "Remote" Calls

There is a Lupine-translation-time way to specify that all calls through a remote
interface are to be only interMDS calls.  This option results in much faster
marshaling at the cost of some generality.  The RPC binder will check that
interMDS stubs are in fact bound in the same machine.  (Furthermore,
encryption is less useful now, although authentication is still needed.)  Of
course, regular stubs can always make (slower) interMDS calls as well.

InterMDS parameter records will be sent as a block, with no marshaling.  Lupine
will probably issue a warning in this case if any short strings, pointers, or
descriptors are contained in any of the parameters' (sub)types.  Some normally
forbidden types are legal in the interMDS case, for instance, computed variant
records and zones (but not MDSZone).  On the other hand, procedure parameters
do not work unless the marshaler continues to marshal them as a special case.  I
haven't thought enough about interMDS calls to decide all of this yet.  Do
interface variables make sense for interMDS calls?  I think not.  Roy, you've
pondered interMDS the most, what's reasonable in these situations?

[Aside:  it's possible to make the interMDS test at binding time rather than
translation time.  The cost would be some extra marshaling overhead for both
kinds of calls.  I haven't thought about it much.  Is there any interest in this
possibility?  It gets more complicated if we allow for the eventual possibility of
multiple MDSes (specifically, both local and remote MDSes) exporting items to
the same remote interface.]


Conclusion

There is a lot of work to do here.  Your comments on what you find crucial,
important, unnecessary, and ridiculous are requested.  It will help me set
priorities.  None of this planning is set in concrete, and I expect a lot to change
once Lupine has real clients.  Please bring any oversights or hidden problems to
my attention.  Sample interfaces are graciously accepted for testing.


					Thanks,

						Bruce
*start*
02044 00024 US 
Date: 21 Sept. 1981 1:57 pm PDT (Monday)
From: Kolling.PA
Subject: FS7, etc.
To: taft, mbrown
cc: kolling

1. Is there any reason to logout AC's conversation id at the end of each
transaction or can I keep it around ad infinitum?

2. Any suggestions for how AC can know the password it needs to establish itself
as a privileged client without having this password sitting around where
someone evil can get at it?  The best I could think of was having it passed across
by FS at system initialization time, which means it still sits in some command
file.

3. The volumeId in Open isn't totally superfluous (sp?) as it is used by AC, even
though Pilot ignores it.  Thought:  what if a client creates a file on volume foo,
then two weeks later opens it but saying it is on volume bar.  Is there any check
that the client is telling the truth?  If not, his/her space allocation may come out
of the wrong volume group.  No harm I suppose, but..... Similarly the file access
stuff that uses the owner database (associated with the volume group) would be
wrong.

4. Ref your comment on closing a file.  We may want to put this in as an option
to free our internal structures.  Juniper/ftp sent the system west when clients
with truly enormous directories tried to touch all their files;  it was "fixed" by
forcing a checkpoint, which since it was ftp didn't matter, but we obviously
can't do that in the general case.

5. No way can an owner write its space quota. tsk, tsk.

6.  A discussion about access lists again?  I don't believe it.....:  I was thinking
that the owner lists mean as follows for owner properties (we won't even discuss
their effect on file properties):

	owner create		who can create files
	owner modify	who can modify the owner access lists

I will change over to your way, which I think is:

	owner create		who can create files
	owner modify	who can modify the owner create list

(Of course, an asserted AW can do anything).  N.b., I let anyone in either owner
access list read the owner entry.

Karen

*start*
00460 00024 US 
Date: 21 Sept. 1981 2:35 pm PDT (Monday)
From: Kolling.PA
Subject: wheels
To: taft, mbrown
cc: kolling

I think I prefer the assertion of AW state to stay in AC rather than in the
ClientMap, so that all the privilege control stays together.  (We can have a call
AC.IsAssertedAlpineWheel[conversationID, transID] if we need it)  AC could
handle the special system conversationID by a check and always treat it as an
asserted AW.

Karen

*start*
00167 00024 US 
Date: 21 Sept. 1981 3:18 pm PDT (Monday)
From: kolling.PA
Subject: wheels again
To: taft, mbrown
cc: kolling

Yes, keep it in the client map.

*start*
00408 00024 US 
Date: 21 Sept. 1981 3:24 pm PDT (Monday)
From: kolling.PA
Subject: wheels again again
To: taft, mbrown
cc: kolling

Is the ClientMap going to field AssertAlpineWheel completely itself?  I.e., will it
know the AW list name and call "something" to do IsMember? or will it call
AC.IsAlpineWheel?  If the former, the clientmap has to know the name of the
server-specific AW list.

Karen

*start*
01288 00024 US 
Date: 21 Sept. 1981 3:54 pm PDT (Monday)
From: Taft.PA
Subject: Re: FS7, etc.
In-reply-to: Kolling's message of 21 Sept. 1981 1:57 pm PDT (Monday)
To: Kolling
cc: taft, mbrown

1. ConversationIDs can be kept around forever.

3. When we open an existing file, Pilot's File.GetAttributes will tell us what
volume it's actually on, and that's the information we'll use for AccessControl
operations involving that file.  That's why it's ok to ignore the client's volume
argument.

For consistency with the future, we might have Open fail if the volume passed
by the client differs from the volume where the file actually resides (rather than
just ignoring the volume argument).  This would force clients to remember
VolumeIDs in addition to FileIDs and FileStoreRNames; I'm uncertain whether
this is really a good idea.

4. We can cope with giant enumerations either by providing an explicit Close
operation or by implementing the OpenFileMap in such a way that it "can't"
overflow.  The explicit Close does seem easier.

5, 6.  Oh, sigh.  Do it whatever way you want.  We can always change it later if
we don't like it.  I thought having the owner modify list control changes to the
space allocation was perfectly reasonable; but your way is equally reasonable.
	Ed

*start*
00378 00024 US 
Date: 21 Sept. 1981 3:59 pm PDT (Monday)
From: kolling.PA
Subject: Re: FS7, etc.
In-reply-to: Taft's message of 21 Sept. 1981 3:54 pm PDT (Monday)
To: Taft
cc: Kolling, mbrown

But, if the owners can set their own space quotas why bother to have quotas at
all?  I can't munge in and set my Ivy quota, can I?  (If I can, my space problems
are over.....)

*start*
00535 00024 US 
Date: 21 Sept. 1981 4:00 pm PDT (Monday)
From: Taft.PA
Subject: Re: wheels again again
In-reply-to: kolling's message of 21 Sept. 1981 3:24 pm PDT (Monday)
To: kolling
cc: taft, mbrown

ClientMap.EnableAlpineWheel just remembers the bit it was passed.  I think
we've agreed that AlpineAccess.AssertAlpineWheel will just call
AccessControl.AssertAlpineWheel; AccessControl will do the access check and put
the answer into the ClientMap itself.  Thus the wheel RName needs to be known
only by AccessControl.
	Ed

*start*
00884 00024 US 
Date: 21 Sept. 1981 4:31 pm PDT (Monday)
From: Taft.PA
Subject: Re: FS7, etc.
In-reply-to: kolling's message of 21 Sept. 1981 3:59 pm PDT (Monday)
To: kolling
cc: Taft, mbrown

The mode of usage I had in mind was that the owner modify list would include
the owner's administrator, not the owner him/herself, and that the administrator
would be able to modify the owner's create list and space quota.   This would
permit us to have administrators who aren't wheels.

Your model, which is equally valid, is that the owner modify list includes the
owner him/herself, and that the owner is permitted to change only the create
list.  Administration is entirely separate, and requires that all administrators be
wheels.

I'm perfectly happy to adopt your model (if indeed I've described it correctly),
and will change the FileStore documentation appropriately.
	Ed

*start*
00414 00024 US 
Date: 21 Sept. 1981 4:47 pm PDT (Monday)
From: kolling.PA
Subject: Re: FS7, etc.
In-reply-to: Taft's message of 21 Sept. 1981 4:31 pm PDT (Monday)
To: Taft
cc: kolling, mbrown

I liked your idea of the administrator not being a true wheel, until I realized
that then there was no way for the administrator to do AddOwner.  I think I'll
leave it the old way (modify can twitch both lists).

*start*
00322 00024 US 
Date: 21 Sept. 1981 4:51 pm PDT (Monday)
From: kolling.PA
Subject: Re: FS7, etc.
In-reply-to: Taft's message of 21 Sept. 1981 4:31 pm PDT (Monday)
To: Taft
cc: kolling, mbrown

Sigh.  I've changed my mind half way.  Let's let people in the modify list only
change the create list, not both lists.

*start*
00759 00024 US 
Date: 24 Sept. 1981 5:30 pm PDT (Thursday)
From: Taft.PA
Subject: Re: deadlock error
In-reply-to: kolling's message of 24 Sept. 1981 3:52 pm PDT (Thursday)
To: kolling
cc: mbrown, taft

It feels like an abstraction failure to me.  In any event, unwinding the error
should leave the abstraction in a good state.

If you're asking what AccessControl should do if it gets a LockFailed error from
calling AlpineFile, I'd say that you should clean up your state and raise
LockFailed yourself with the same argument.  (Alternatively, you could REJECT
the error and let it pass through to your caller, who would certainly have to
catch it; this violates the Levin signalling guidelines, but I don't see any harm
from that in this case.)
	Ed

*start*
00591 00024 US 
Date: 25 Sept. 1981 3:29 pm PDT (Friday)
From: kolling.PA
Subject: what I currently believe about Locks
To: mbrown, taft
cc: kolling

AC wants to explicitly lock both individual file pages and an entire file;  these
locks should be indistinguishable from the locks that AlpineFile or whatever will
get for the same entities.  I also expect to be able to release the read locks on the
individual file pages.

AC also wants to both read and write lock "strange objects" corresponding to a
VolumeGroup.  This makes life simple during (un)registering volumeGroups, etc.

*start*
01213 00024 US 
Date: 25 Sept. 1981 3:49 pm PDT (Friday)
From: Taft.PA
Subject: Re: what I currently believe about Locks
In-reply-to: kolling's message of 25 Sept. 1981 3:29 pm PDT (Friday)
To: kolling
cc: mbrown, taft

File locks are explicitly set by an argument to AlpineFile.Open, and may be
upgraded by AlpineFile.SetLockOption.

Page locks are implicitly set by AlpineFile.Read/WritePages operations on the
individual pages.  We don't provide an explicit page lock operation, and I'm
doubtful whether we need to (why bother locking a page if you aren't going to
at least read it?)  Note that you can set an update or write lock during a
ReadPages operation if you want.

AlpineFile does not presently export an explicit "unlock" operation; locks are
released implicitly when a transaction terminates.  I suppose there's no harm in
exporting a procedure to release read locks, since by doing so a client can screw
only itself (the same cannot be said about update and write locks, however). 
Unless Mark objects, I will add this to the interface.

For locking non-file objects, you are welcome to deal directly with the lock
manager itself via the Lock interface specified in LockDesign0.bravo.
	Ed

*start*
00478 00024 US 
Date: 25 Sept. 1981 4:01 pm PDT (Friday)
From: Kolling.PA
Subject: Re: what I currently believe about Locks
In-reply-to: Taft's message of 25 Sept. 1981 3:49 pm PDT (Friday)
To: Taft
cc: kolling, mbrown

1. "why bother locking a page if you aren't going to at least read it": because
that page may be in my buffer cache, and if I don't modify it, I won't ever do
IO.

2. I'm using locks for queueing, that's why I need to get them before the actual
IO.

*start*
00620 00024 US 
Date: 4 Sept. 1981 4:12 pm PDT (Friday)
From: kolling.PA
Subject: Here's Mark's solution for CheckAccessFile.
To: Taft
cc: mbrown, kolling

FS.OpenFile makes an OpenFileID at the beginning of OpenFile.
FS calls AC.CheckAccessFile[openFileID blah blah].
AC calls FileProperties.something to read the access list it wants[openFileID].
FP calls into FS to read the leader page, which makes the locking and looking in
the log happen right.

I'll go ahead with the extra stuff for the access lists as you suggest, unless Mark
says differently.  I think this resolves all the questions raised?

Karen

*start*
00480 00024 US 
Date:  8-Oct-81 17:15:07 PDT (Thursday)
From: Kolling.PA
Subject: Locking strange things
To: mbrown
Reply-To: Kolling
cc: Kolling

I want to lock "volume groups" to allow registering them when the system is running.  I assume that the entity would be the volumeGroupID and the subentity is some constant.  How do I guarantee that the LockIDs I use don't get confused with LockIDs for other things?  By instantiating a lock manager of my very own?  

Karen
*start*
00373 00024 US 
Date:  8-Oct-81 17:30:04 PDT (Thursday)
From: MBrown.PA
Subject: Re: Locking strange things
In-reply-to: Your message of 8-Oct-81 17:15:07 PDT (Thursday)
To: Kolling
cc: MBrown

A VolumeGroupID should be globally unique, so there is not any possibility that it will conflict with a FileID or anything else that might go into that field of a LockID.
*start*
00595 00024 US 
Date: 13 Oct. 1981 1:08 pm PDT (Tuesday)
From: Taft.PA
Subject: Re: exported types
In-reply-to: MBrown's message of 13-Oct-81 12:53:12 PDT (Tuesday)
To: MBrown
cc: Taft, Kolling

I agree with you that hiding representations is pointless in internal interfaces. 
Unfortunately, the case at hand, OpenFileHandle, IS a public type, and I believe
making it opaque is appropriate in this case.

Perhaps we should have a meeting to discuss interface design conventions.  You
two are far more experienced in designing Mesa interfaces than I am, so I might
learn something.
	Ed

*start*
00874 00024 US 
Date: 13-Oct-81 12:53:12 PDT (Tuesday)
From: MBrown.PA
Subject: Re: exported types
In-reply-to: Taft's message of 13 Oct. 1981 8:50 am PDT (Tuesday)
To: Taft
cc: Kolling, MBrown

Another possibility is to make OpenFileHandle concrete in the interface.  My experience with exported types is that they are a big pain, largely due to the poor debugger support but also because the semantics aren't quite right.  So my attitude is that it may be worth the effort to make the types in public interfaces opaque, but it is often not worth the effort for internal interfaces.

Karen, for the purposes of getting your stuff to compile, you should feel free to make edits to the agreed-upon interfaces, keeping your private versions on a separate subdirectory or something.  At least, that is what I've been doing.  We can merge in the changes later.

	--mark
*start*
02222 00024 US 
Date: 15 Oct. 1981 9:38 am PDT (Thursday)
From: Swinehart.PA
Subject: File properties
To: Kolling, MBrown, Taft
cc: Swinehart

I think the tradeoffs you've made in the Alpine design are just right.  This system should really do the trick for us.  The one decision I was puzzled about is not a big deal, but I wondered about the reasons -- the decision to allow only a fixed number of file properties.

Although as far as I know I'm the only person ever to use them regularly, I have found the Alto system's willingness to support an arbitrary number of arbitrary (theoretically, registered) leader page properties very valuable.  It allows me to attach system-specific version information, comments, checksums, etc., to files whose format I have no control over (e.g., to .RUN files produced by BLDR, or .BCD or .BOOT files produced by the compiler, linker, or whatever -- or just to Tioga-edited text files.)  With directory systems to be provided outside the scope of the system, the ability to retrofit properties that could assist indexing and directory management becomes even more important.  Much of that could be provided elsewhere, but some of it might be associated with high-level scavenging, and that would have to go with the file.

(Just remembered: Eric Schmidt used this capability to store full path names of Bringover/Smodel'ed files in local file leader pages, with very nice results.)

The obvious response is that if only one or two people used these features they weren't very important.  I think few people used them because the shared file systems and FTP were not willing to preserve them.  I could have done a very nice Spruce version release management system by annotating the released object files themselves.  As it was, I got some limited benefit from the local capabilities alone.

I guess it depends on where you're going to store the properties and how much room you have for them, but I'd vote for keeping something like the Alto/Pilot leader page notion -- maybe even going as far as the fixed number of fixed-sized properties followed by a jungle of variable-length ones.  It's a way to impose a small amount of orthogonal semantics on a file, after the fact.

*start*
02327 00024 US 
Date: 15-Oct-81 10:19:14 PDT (Thursday)
From: MBrown.PA
Subject: Re: File properties
In-reply-to: Swinehart's message of 15 Oct. 1981 9:38 am PDT (Thursday)
To: Swinehart
cc: Kolling, MBrown, Taft

Thanks for your comments.  I'm can't say precisely how Karen and Ed feel about this, but here is my rationale about file properties:

1) I feel that it is very important to keep the per-file fixed overhead low.  I don't want to pay for features that I never use.  Alpine is intended to have a nicer file system layered on it, and this system is likely to have its own ideas about most of the built-in features of files.

At the same time, I feel that Pilot files are too primitive (no properties beyond type, temporary, and immutable.)  The obvious compromise at this time is a single leader page per file.  In our current design, this page is pretty full (the access lists, the name of the file's owner, and the file string name are the main consumers of space.)  The current design is VERY simple: all items, even variable length ones, are found at fixed locations in the leader page.

The Pilot redesign includes the ability to extend a file at both ends (as at SAIL, with negative page numbers.)  This would make it possible for some files to have more leader pages than others.  Extra leader pages could be used to store optional file properties with more complex formats.

2) I like the view that file properties are logically part of a database of information, keyed by file ID.  So why do we use leader pages at all?  The motivation seems to derive primarily from reliability considerations: the information in a leader page is so precious that losing it implies that the associated file is worthless.  Hence storing them in close proximity makes it likely that they survive or fail together.  In a system like Alpine, which takes other precautions to ensure reliability, it is not clear that this argument carries much weight.  The secondary motivation is performance: if some information (such as acess control lists) must be consulted on every file access, then it makes sense to cluster it with the file.

I have a feeling that you'd be happy with a good database system to store your extra file properties.  The sooner Alpine is finished, the sooner we'll have that database system.

	--mark
*start*
01703 00024 US 
Date: 12 Oct. 1981 7:08 pm PDT (Monday)
From: Nelson.PA
Subject: Supporting multiple versions of remote interfaces
To: Birrell
cc: Taft, MBrown, Kolling

I assume that RPC clients are allowed to export the same interface type from the
same instance several times as long as the VersionRanges are not identical.  For
example,

AlpineWorker [5,9]
AlpineWorker [3,6] and
AlpineWorker [1,2]

might all be exported from the same server, and the binder's job is to match
importers with a suitable exporter.

I suggest that it may also be advisable to include Lupine's protocol version in
this matching algorithm.  For example, assume that parameter marshaling changes
(incompatibly) for some performance reason.  I can imagine RPC clients
generating new stubs to get the increased speed for most of their users, but not
being able to force some users to update (for the same reasons that they have
multiple versions of their own interfaces).  In this case, the client's interface
type has not changed, but the underlying protocol has.  If the protocol version is
included with the client's version, all works well:

AlpineWorker [5,9] [1,2]
AlpineWorker [5,9] [3,3]

The client exports both interfaces by calling the Control modules for each (which
were generated by the two versions of Lupine).  It is possible, as well, to put
this problem in the client's hands by making him increase his VersionRange
whenever Lupine changes.  This is not too difficult, but may be undesireable.

The purpose of this note is to [1] inquire about nonidentical version range
exports, [2] point out the Lupine protocol twist, [3] see if any of you think this
is something to worry about.

						Bruce 
*start*
01435 00024 US 
Date: 14 Oct. 1981 10:59 am PDT (Wednesday)
From: Nelson.PA
Subject: Change to RPC.mesa
To: Birrell, Taft
cc: MBrown, Kolling, Nelson

Ed's CedarRpc uses a record to hold the parameter zones, and I think this idea is
good enough to adopt outright.  To make it work properly, tho, the RECORD
must be defined in one public place, and RPC is the most natural.  I suggest that
the following two defs be added.  They don't effect Andrew at all; only Lupine
and clients use them:

In RPC.mesa:

-- These Zones are used by stubs for parameter storage.
Zones: TYPE = RECORD [
    collected: ZONE←NIL,
    heap: UNCOUNTED ZONE←NIL,
    mds: MDSZone←NIL ];

-- The StandardZones are assigned by RpcControl.Import&ExportInterface.
StandardZones: Zones = [];

In addition, to clarify the existence of a default for InterfaceName, I also suggest
adding the following constant, which Andrew can again ignore:

-- An interface's UniqueName is assigned by RpcControl.Import&ExportInterface.
UniqueName: InterfaceName = [];



RpcControl would then have these procedures:

  ExportInterface: PROCEDURE [
    user: Principal,
    password: EncryptionKey,
    interface: InterfaceName←UniqueName,
    parameterStorage: Zones←StandardZones ];

  UnexportInterface: PROCEDURE;

  ImportInterface: PROCEDURE [
    interface: InterfaceName←UniqueName,
    parameterStorage: Zones←StandardZones ];

  UnimportInterface: PROCEDURE;




*start*
01442 00024 US 
Date: 14 Oct. 1981 11:55 am PDT (Wednesday)
From: Nelson.PA
Subject: Buffer allocation faults
To: Birrell, Taft
cc: MBrown, Kolling, Nelson

It is nearly certain that Alpine will specify a special heap zone for buffers
(descriptor bodies).  Lupine will probably allocate descriptor bodies in this way
(and other storage similarly):

RawStorage: TYPE = MACHINE DEPENDENT RECORD [
	words (0): SEQUENCE COMPUTED CARDINAL OF WORD ];

-- The wire protocol for a descriptor is (say) [length, descriptorBodyData...].

bufferVar: LONG DESCRIPTOR FOR ARRAY OF Alpine.Page =
      DESCRIPTOR[
	  zones.heap.NEW[RawStorage[length*SIZE[Alpine.Page]]]↑,
	  length]

Notice that there is no catchphrase on this NEW (or the invisible FREE).   I'm
open to suggestions, since heap failure on a server could bring down the server
via a remote call.

One idea:  Lupine can put an ANY on the NEW, and translate it into
CallFailed[storageFailure].  Note that it's impossible to catch specific signals here.

Second idea:  Andrew should put an ANY in the runtime, catching anything
that comes from a Dispatcher that he doesn't already handle.

Other signals that Lupine can't recover from include: Rope faults, Atom faults,
and List faults.  Is it better to have catchphrases increasing the size of the stubs,
or to put one ANY where it will have the same effect?

I'm a novice in this department, what do you two veterans say?

					Bruce
*start*
01292 00024 US 
Date: 14 Oct. 1981 12:28 pm PDT (Wednesday)
From: Nelson.PA
Subject: NIL and zero length values
To: Birrell,
cc: Taft, MBrown, Kolling
cc: Nelson

Andrew,

One of the early problems that Courier (and Envoy?) had is that they treated
NIL strings like strings of 0 length.  Similarly for a descriptor with NIL base. 
Clients (depending on the difference) deep-sixed.

My question concerns how to represent NIL.  The obvious wire protocol for
strings is [maxlength, length, characters].  Liaison used
length=LAST[CARDINAL] to mean NIL, but this causes problems for the largest
string.  Should this be continued, or should an escape be used (eg, IF
length=LAST[CARDINAL] THEN nextWord is NIL flag).  Note that while the
escape flag only needs to be one bit, the packing is not worth the trouble and a
full word will be used.

For TEXT, this problem disappears since the NAT index leaves the top bit for the
flag.

For descriptors, it seems likely that LONG indices will eventually be valid, and
that 2 words of length should be used from the start.  Thus an escape takes a yet
a third word if LAST[LONG CARD] is not pressed into service as above.

Ropes, of course, have LONG INT indices, leaving the top bit again.  I don't
know if NIL atoms are permissible.

					Bruce
*start*
01013 00024 US 
Date: 14 OCT 1981 1654-PDT
From: NELSON.PA
Subject: Beware of the warning in the second paragraph should the # of words in a pagerun ever get too large...
To:   Taft, MBrown
cc:   Kolling

Date: 14 Oct. 1981 4:48 pm PDT (Wednesday)
From: Satterthwaite.PA
Subject: Re: Sequence strategies
In-reply-to: Your message of 14 Oct. 1981 12:03 pm PDT (Wednesday)
To: Nelson

I think you are right that the second is not legal as it stands, nor can it be made
legal without introducing a type identifier.  Then the choice seems to come down
to whether you want to talk about sequences of WORDs or sequences of
Alpine.Page's.   Given the declaration of bufferVar, the latter seems more
natural.  I think the compiler is neutral on this (though I have forgotten the
details of the interactions, if any, between (multiargument) DESCRIPTOR and
(computed) SEQUENCE).

Be aware that NEW will fail (probably without complaint) if the number of
WORDS requested exceeds 2↑16-1, however it is computed.

Ed

*start*
02169 00024 US 
Date: 14 Oct. 1981 7:29 pm PDT (Wednesday)
From: Nelson.PA
Subject: Short Ropes and RNames
To: Taft, Atkinson
cc: MBrown, Taft, Kolling, Nelson

I know this is discussing an optimization before it's time, but the fact is that
Lupine is going to generate significantly better (faster and smaller) stubs when
the cardinality of a sequence's bounds type is reasonable.  For example, if TEXT
had the field


text: PACKED SEQUENCE maxLength: [0..shortStringLength) OF CHARACTER
	instead of
text: PACKED SEQUENCE maxLength: CARDINAL OF CHARACTER. 


The reason for such restricted definitions is that dynamic length types can
become small enough that any corresponding parameters are guaranteed to fit
into one packet.

In FileStore8, this applies to RNames (which are currently restricted to 64), and
to Strings (which appear to be limited to around 100 characters).

This message is just to provoke thought about whether or not it is reasonable to
define a short Rope or String type.  The first thing in my head is to define

ShortROPE = Rope.ShortRef;

ShortRef: TYPE = REF shortText RopeRef;

     
  RopeRep: TYPE = RECORD
    [SELECT tag: * FROM
       text =>
          [length: NAT,
	   text: PACKED SEQUENCE max: CARDINAL OF CHARACTER],
       shortText =>
          [length: [0..shortRopeLength),
	   text: PACKED SEQUENCE max: [0..shortRopeLength) OF CHARACTER],
       node => [SELECT case: * FROM
       		  substr  => [size: Int, base: Ref, start: Int], 
       		  concat  => [size: Int, base,rest: Ref, pos: Int],
       		  replace => [size: Int, base,replace: Ref,
		              start,oldPos,newPos: Int],
       		  object  => [size: Int, base: REF, fetch: FetchType,
                   	      map: MapType, pieceMap: PieceMapType]
       		  ENDCASE]
       		ENDCASE];

By making this RopeRep a suitable aligned machine dependent record, the
shortTest variant will be bitwise identical with its friends, and the standard
operations can be used.  Trying to lengthen a shortText with a standard rope
operation would probably cause a fault.   There are a lot of obvious problems
with this; this is just a half-baked suggestion.

*start*
03731 00024 US 
Date: 14 Oct. 1981 9:54 pm PDT (Wednesday)
From: Atkinson.PA
Subject: Re: Short Ropes and RNames
In-reply-to: Nelson's message of 14 Oct. 1981 7:29 pm PDT (Wednesday)
To: Nelson
cc: Taft, Atkinson, MBrown, Kolling

First, I really do not understand why whatever program is performing the copy
does not dynamically check for the short case.  I would like to see the code that
you intend to generate for the various cases.  My own feeling for what should
be generated to copy a rope is along the lines of (modulo enough LOOPHOLEs to
make the compiler happy, and neglecting stupid mistakes):

	-- to copy r: ROPE into a buffer at p: LONG POINTER TO CARDINAL
	-- plimit: LONG POINTER TO CARDINAL has limiting address
	-- assume that at least one word is available at start
	IF r = NIL
	    THEN {p↑ ← 0; p ← p + 1}
	    ELSE
		{WITH r SELECT FROM
		    t: Text =>
			{words: CARDINAL = (t.length+3)/2;  -- allow for length
			 np: LONG POINTER TO CARDINAL = p+words;
			 IF LOOPHOLE[np, LONG CARDINAL]
				< LOOPHOLE[plimit, LONG CARDINAL]
			    THEN 
				{-- short copy
				 p↑ ← t.length;
				 BLT[to: p+1, words: words-1, from: @t[0]];
				 p ← np;
				 };
			    ELSE GO TO long;
		    ENDCASE => GO TO long;
		  EXITS long => p ← LongRopeCopy[r, p]};

The above code assumes that you would like to keep the amount of storage used
small.  For (possibly) faster code one could assume that the short case was always
small enough to fit in (let's say) 32 characters, and storage space in the buffer is
not an issue.  Further suppose that we are working with current Ropes.  Then
the code for rope copying might be:

	-- to copy r: ROPE into a buffer at p: LONG POINTER TO CARDINAL
	-- assume that there is enough room at the start for the short case
	ShortWords: CARDINAL = 2+(32/2); -- room for short case
	IF r = NIL
	    THEN {p↑ ← 0; p ← p + ShortWords}
	    ELSE
		{WITH r SELECT FROM
		    t: Text =>
			{IF t.length <= 32
			    THEN 
				{-- short copy
				 BLT[to: p, words: (t.length+5)/2, from: t];
				 p ← p + ShortWords;
				 };
			    ELSE GO TO long;
		    ENDCASE => GO TO long;
		  EXITS long => p ← LongRopeCopy[r, p]};

I would guess that one of the two methods given above is about as good as you
will get even if you had the possibility of a short variant.  If the knowledge of
static offsets in the buffer is important then you can test for all of the ropes
being short before starting any copying, but you must still allow for the long
cases for general ropes.  Note that you MUST NOT avoid computing the # of
words to BLT, since you could run off the end of the rope into an unmapped
space (although if a ByteBlt is supported in microcode then you can get by with
less computation).

Second, Ropes are complex enough without adding more cases to dynamically
check for in every Rope operation.  I am not inclined to add to the cost and
complexity of Rope operations to gain a small improvement in RPC speed,
especially since it may slow down the system as a whole.  I would like to point
out that having three cases instead of two does not seem to me to be making
Lupine's job any easier.  However, I may be missing something again.

In reading your message over, I got the impression that your shortest Rope
variant would become the type used for a number of applications.  Although one
could see this as being possible, I think that anyone who used this assumption
and wanted very high efficiency would be unhappy with Ropes for the cost of
their generality.

One final comment: it is a bad idea to demand extreme efficiency, ease of use,
generality, and safety in a single package.  Attempting to satisfy all such
requirements will result in a package that satisfies no one.

Russ

*start*
00778 00024 US 
Date: 15-Oct-81  9:51:48 PDT (Thursday)
From: MBrown.PA
Subject: Re: Short Ropes and RNames
In-reply-to: Nelson's message of 14 Oct. 1981 7:29 pm PDT (Wednesday)
To: Nelson
cc: Taft, Atkinson, MBrown, Kolling

I'm with Russ on this.  The stub should check the rope length at runtime and if it is too long, then ERROR.  You should invent some means for a programmer to declare (at stub-compile time) her willingness to bound the length of a Rope (or whatever).  Ideally, the type system would give you a way of expressing this while still getting something compatible with Rope, but we aren't there yet.  Ed Satterthwaite and Jim Donahue should be part of this discussion, just for their information about how the present type system limits you.

	--mark
*start*
01578 00024 US 
Date: 15 Oct. 1981 10:26 am PDT (Thursday)
From: Nelson.PA
Subject: Short Ropes
To: Atkinson
cc: MBrown, Taft, Kolling, Nelson

So much for talking about optimization before its time.  My main point seemed to
be missed by all, because I did not emphasize it enough.  The fact that only
`length' characters get copied, that long cases get properly handled, and that
short cases don't look much different than the short versions of long cases are all
true.  I never said or meant anything different.  However, what a static short
declaration does is allow a static determination of the single packet call case. 
This information allows other optimizations to happen, such as avoiding
copying all kinds of static data from the packet to the local frame because there
might be another packet.  (Yes, even in this latter situation you can (and
Lupine does) treat the two cases separately, generating a lot more code to do it.)

Of course, I can simply declare that a certain type name means short text, and
raise ERROR at runtime otherwise.  I realized this at the outset, but my
invention of a short text type for Lupine seems a little arbitrary, and the
existence of Grapevine short strings, Karen's short stuff, and so on call for a
generally-accepted method of doing so.  I succeeded in generating some
discussion about the issue, but nothing has settled, as I expected.  Lupine is
happy to generate general-case code in the meantime.

I will send this round of msgs to Ed and Jim--an excellent suggestion--after they
have settled.  

					Bruce

*start*
00846 00024 US 
Date: 15 Oct. 1981 6:08 pm PDT (Thursday)
From: Birrell.pa
Subject: Re: NIL and zero length values
In-reply-to: Nelson's message of 14 Oct. 1981 12:28 pm PDT (Wednesday)
To: Nelson
cc: Birrell, Taft, MBrown, Kolling

I don't see anyone having a string whose length is LAST[CARDINAL], so using
that for NIL might be ok.  On the other hand, for DESCRIPTOR the length could
easily be LAST[CARDINAL] (e.g. PACKED ARRAY OF BOOLEAN), so some
other representation seems needed.  I don't see much alternative to using an extra
word.  You could use an escape mechanism if you can stand the complexity: 
LAST[CARDINAL] means NIL but LAST[CARDINAL]-1 means the true length is
in the next word.  Then you only pay the extra word if the array is already
very large.  This might also be reasonable for optimizing LONG indices.

Andrew

*start*
00510 00024 US 
Date: 15 Oct. 1981 6:10 pm PDT (Thursday)
From: Birrell.pa
Subject: Re: Supporting multiple versions of remote interfaces
In-reply-to: Nelson's message of 12 Oct. 1981 7:08 pm PDT (Monday)
To: Nelson
cc: Birrell, Taft, MBrown, Kolling

I think the view that a different interface type can be used to handle such
incompatible changes is probably the best.  The alternative seems to add
unneeded complexity (and reduces the ability for error checking such as
duplicate exports).

Andrew

*start*
00425 00024 US 
Date: 15 Oct. 1981 6:14 pm PDT (Thursday)
From: Birrell.pa
Subject: Re: Buffer allocation faults
In-reply-to: Nelson's message of 14 Oct. 1981 11:55 am PDT (Wednesday)
To: Nelson
cc: Birrell, Taft, MBrown, Kolling

I can't think of any solution for this other than passing in the errors as
parameters of ExprotInterface with the zones, which sounds very ugly.  We do
need a solution, though!

Andrew

*start*
00708 00024 US 
Date: 16 Oct. 1981 10:17 am PDT (Friday)
From: Nelson.PA
Subject: NIL descriptors
To: Birrell
cc: Taft, MBrown, Kolling, Nelson

If you're willing to go along with LAST[CARD] for the NIL string, then I
believe it works with little danger for descriptors too.  The reason is that
indexType-less descriptors can only be constructed using the 2-arg form of
DESCRIPTOR, which requires a length.  Thus the probability of this failing
dynamically is in the same ballpark (yeah, Dogers!) as a maxLength string.  The
fact that the static symbol table index type for dynamic descriptors is CARD
makes no difference at runtime.

Does this clarify things, or did I miss something?

						Bruce

*start*
00780 00024 US 
Date: 16 Oct. 1981 10:42 am PDT (Friday)
From: Birrell.pa
Subject: Re: NIL descriptors
In-reply-to: Nelson's message of 16 Oct. 1981 10:17 am PDT (Friday)
To: Nelson
cc: Birrell, Taft, MBrown, Kolling

The difficulty with descriptors is that it's (quite) reasonable for someone to
declare

m: LONG POINTER TO PACKED ARRAY CARDINAL OF BOOLEAN = ......;

and then pass DESCRIPTOR[m] as a value-parameter;  you shouldn't confuse that
case with NIL.  If you would confuse that case with NIL, I'd vote for a runtime
check to complain if you're about to do so.  The reason I'm willing to believe in
the absence of maxlength strings is that they occupy 32k words of memory.  On
the other hand, they're not impossible so maybe all the same remarks apply.

Andrew

*start*
00472 00024 US 
Date: 16 Oct. 1981 3:23 pm PDT (Friday)
From: Nelson.PA
Subject: Re: NIL descriptors
To: Birrell
cc: Nelson, Taft, MBrown, Kolling

I spoke with Ed, and he agrees that while DESCRIPTOR[m↑] (slight error) is
legal, in practice the compiler probably blows it on the CARD.  It also turns out
that SEQUENCES are likely to allow LONG bounds types soon, and thus I will
adopt the 2 word philosophy to start with, making LAST[LONG CARD] be NIL.

Bruce



*start*
01520 00024 US 
Date: 19 Oct. 1981 1:16 pm PDT (Monday)
From: Taft.PA
Subject: Exported types
To: MBrown, Kolling
cc: Taft

After consultation with Satterthwaite, I have concluded that the style of usage of
exported types exemplified by the Alpine defs files is perfectly ok.  That is, it's
ok to define TransID as an abstract type in AlpineEnvironment, and then define
types in AlpineFile, AlpineTransaction, etc., equal to that type.

However, the implementation module that exports the corresponding concrete
type must export it to ALL interfaces that refer to the abstract type.

A related issue has to do with the definition of types that are interpreted
differently in different contexts, such as the LockID.  Mesa currently has a
restriction of only one concrete type per abstract type.  In this case, I propose we
do the following:

1) Define LockID as an abstract type in AlpineEnvironment (or wherever is
appropriate; currently we don't export any operations that deal in LockIDs).

2) Define it as a concrete type in exactly one place, using some noncommital
representation such as ARRAY [0..SIZE[LockID]) OF UNSPECIFIED.

3) In the defs files for programs that interpret LockID in a specific way, define
new types FileLockID, FilePageLockID, DataBaseLockID, etc, with whatever
representation is appropriate; and also define inline procedures that "convert"
between the specific and noncommital representations using LOOPHOLE.

I'll go ahead and massage the defs files to test out this approach.
	Ed

*start*
02318 00024 US 
Date: 20-Oct-81 11:48:58 PDT (Tuesday)
From: MBrown.PA
Subject: Design for Alpine online backup
To: Kolling, Taft
cc: MBrown

Ed, you mentioned in your Dealer that we don't have a design for backup, and that this is one of the things that will get done in the "tail" of Alpine development.  I have given some thought to backup, and I think I have a plausible design.  Furthermore, I think it is rather important that backup be done early in the implementation, because of Alpine's goal to provide high reliability storage.

My design for backup is based on online pack copying for Alpine volumes and either tape or disk backup of logs.  Alpine volume backup will work by having one extra drive and k sets of backup packs (k = 2?).  Ron will mount one new backup pack each morning, in an obvious rotation.

The pack copying process runs during a relatively quiet period (at night?).  It begins by performing a warm shutdown of the system.  This aborts all in-progress transactions and forces all disk writes.  A special record is written into the log to mark this event.  The system then comes back online, with an internal flag set to show that pack #j is in the process of being copied, and a process is spawned to do the copying.

The copy reflects the state of the volume at the shutdown point.  To implement this, all writes to the copy volume first call a procedure implemented as part of the copy procedure.  It consults a bitmap (150 pages of vmem for a T-300) to determine if the pages have already been copied  (or maybe the map is done at a logical file level).  If not, they are, and marked as such in the map.  When the call returns, the write may proceed.

Logs may be saved as is, or may be reprocessed to save some space and make them easier to use in media recovery.  Saving logs to disk is attractive in that tapes are relatively unreliable and have small capacity.  If a log is a T-300, then it may take several days to fill, and the log backup can take place in rotation with the pack copying.

The procedure for media recovery is straightforward: find most recent volume copy, get value, replay logs forward and apply updates.  This works for single page and whole-volume failures.  The procedure is more complex if volumes span multiple packs.

What do you think?

	--mark
*start*
00631 00024 US 
Date: 20 Oct. 1981 11:57 am PDT (Tuesday)
From: Kolling.PA
Subject: Re: Design for Alpine online backup
In-reply-to: MBrown's message of 20-Oct-81 11:48:58 PDT (Tuesday)
To: MBrown
cc: Kolling, Taft

Do I understand this correctly: a pack copy is going on, and meanwhile the
system is running and checking before it writes into each disk page to see if that
page has been written yet?  Since it takes such a short time to copy a pack, do
we want the latter extra complexity?  Or am I missing something here?  Also, are
volumes so independent that it's okay to copy one volume out of a volume
group?

Karen

*start*
00756 00024 US 
Date: 20 Oct. 1981 1:47 pm PDT (Tuesday)
From: Kolling.PA
Subject: Re: Design for Alpine online backup
In-reply-to: MBrown's message of 20-Oct-81 12:17:03 PDT (Tuesday)
To: MBrown
cc: Kolling, Taft

By a high speed copy, I assumed a straight
I-know-nothing-about-the-disk-except-#sectors-per-track,-etc. copy with bad
pages put into a bad page table somehow.  This is pretty simple.  Were you
proposing something more complex?  Is the on-line one doing something more
fancy?  (Maybe getting a bad page on the log....) What does the high speed pack
copy have to do that the online one doesn't?  The latter has to handle bad spots
also, yes?  JCopydisk takes one or two pages.  Scaling is easy, all that changes is
a few parameters.

*start*
00948 00024 US 
Date: 20-Oct-81 12:17:03 PDT (Tuesday)
From: MBrown.PA
Subject: Re: Design for Alpine online backup
In-reply-to: Kolling's message of 20 Oct. 1981 11:57 am PDT (Tuesday)
To: Kolling
cc: MBrown, Taft

I think that it might be just as hard to write a really high-speed pack copy as to do the online thing I just described (considering bad spots, the need for a check pass, etc), and the high-speed copy would be harder to maintain (it depends on more low-level details.)  Doing it online has the advantage of scaling better to T-600s or whatever we get next, and is operationally more convenient (Ron can change packs at a reasonable hour if he wants.)  But the offline thing I was advocating before is still a possibility.

The only thing that the volumes of a group have in common is the owner database.  This is just a file from the point of view of the backup system.  So the answer is yes, they are independent.

	--mark
*start*
01522 00024 US 
Date: 20-Oct-81 14:29:24 PDT (Tuesday)
From: MBrown.PA
Subject: Re: Design for Alpine online backup
In-reply-to: Kolling's message of 20 Oct. 1981 1:47 pm PDT (Tuesday)
To: Kolling
cc: MBrown, Taft

I am assuming that the disk is formatted before the copy begins (bad pages are known, the physical and logical volume marker pages are in place, etc.)  A backup pack only needs to be formatted once, as long as the volume it is backing up for is not reformatted.

If you do a copy at the level of physical pages (as the ultra-fast copy must be done in order not to lose revolutions and seeks), then bad pages will cause the volume file map and volume allocation map of the two volumes to differ.  Of course, since you never (actually, rarely) look at the copy, you can omit building the VAM and VFM and just build them (using the scavenger) when you go to read the copy!  But you DO read the copy for the check pass.  So the copy pass and check pass must make consistent decisions about where pages should go.  This is not hard, it just has to be done right.  At any rate, this approach involves using the lowest-level Pilot interfaces; things are strange down there, and will surely change in the redesign.

I was assuming that in the online copy case, the copy is done using high-level disk operations (file level), hence the VAM and VFM are updated and bad pages handled as a matter of course.  This makes the online copy slower, but it should not take more than a few hours at worst...

	--mark 
*start*
04865 00024 US 
Date: 20 Oct. 1981 3:42 pm PDT (Tuesday)
From: Taft.PA
Subject: Re: Design for Alpine online backup
In-reply-to: MBrown's message of 20-Oct-81 12:17:03 PDT (Tuesday)
To: MBrown
cc: Kolling, Taft

In my opinion, simply copying disk packs as the normal way of doing backup is
a total loss, for three reasons:

1. It's nearly impossible to handle bad spots properly.

2. It does not scale upward to handle multi-pack volumes.  (I realize Pilot doesn't
support these now, but I'm hoping it will eventually, for reasons we have
discussed before.)

3. It requires all volumes to be the same size.

I think copying file-by-file at a higher level, as is done in IFS, is the right way
to do business.  I see the following advantages:

1. Backup packs fill up at a lower rate, since you avoid frequent recopying of
files that haven't changed.  For example, on Ivy before the recent split, backing
up the 5 T-300s comprising the primary file system required only 8 backup packs
for an entire month.

2. There is no need to disrupt service.  People might not notice a daily disruption
at 2 am, but programs (e.g., Grapevine's mail archive facility) surely would.  As
we do more and more things in "background", the nighttime hours will become
increasingly busy.

The major disadvantage of the file-by-file approach is that recreating the file
system from backup takes much longer.  For example, reloading all of Ivy (before
the split) would have taken about 12 hours, compared to about 1.5 hours to copy
5 disk packs.  However, this is something we expect hardly ever to do, so I don't
think it's very important.

Now, how do we maintain consistency?  I have the following proposal, which
works at a higher level than Mark's and I think is simpler:

Initially, let's ignore the problems caused by file deletion (I'll get back to this
later); pretend that the only update operations that occur are modifications to
existing files or creation of new ones.

Associate with each file a LastBackupLogID and a WrittenSinceBackup flag.  The
LastBackupLogID is a LogID associated with the most recent transaction that
backed up the file (see below); in particular, it is guaranteed to be less than the
LogID of any update to the file after its most recent backup.  The
WrittenSinceBackup flag is set by every committed update to the file.

You back up a file by copying the entire file to the backup volume, using
normal operations.  You write-lock the file, so internal consistency is preserved
and it is guaranteed that there are no uncommitted updates by other
transactions.  The LastBackupLogID is updated and the WrittenSinceBackup flag
cleared as part of the transaction.  The LastBackupLogID is copied along with the
file.  The entire file must be copied under one transaction; but it is not required
that you copy ALL files under the same transaction.

You use the LastBackupLogID and the WrittenSinceBackup flags to determine
which files need to be backed up.  The former is used to bound the amount of
log you must save and the size of the backup set; and the latter is used to detect
new updates to the file.  The algorithm is fairly obvious, and is essentially how
IFS does its continuous incremental backup.

To reload the file system, you first reload all files from all backup packs.  (It
speeds things up if you start with the most recent backup pack, since then you
need reload only the most recent version of a file updated multiple times during
the lifetime of the backup set.)  While doing so, you compute the minimum
LastBackupLogID; this determines where you start reading the log.

Now you read the log.  For each log entry, you check the file to which it
refers.  If the log entry's LogID is greater than the LastBackupLogID of the file,
you perform the logged action; if less, you skip over it.

A possible drawback of this scheme is that it doesn't perform well for gigantic
files that are updated incrementally.  Since it's possible that data bases will use
such files, we may have to consider this problem.  For backup purposes, we
could break up files into "sub-files" that have individual LastBackupLogIDs.

Now, how do we handle deletions?  The main problem is that the backup set
may contain some files that have been deleted since they were last backed up;
you don't want to reload these at all.  The way IFS handles this is to take a
snapshot of the directory after completing the backup.  I imagine copying Pilot's
volume file map would be equivalent.

This snapshot is used solely for the purpose of determining what files existed
prior to the snapshot.  It needs to be serialized with ongoing transactions
somehow, but I suspect only very weakly; I haven't fully thought this out yet. 
Then, when reloading the file system, you restore only those files listed in the
most recent snapshot, and skip over all the others.
	Ed

*start*
01177 00024 US 
Date: 20-Oct-81 17:39:47 PDT (Tuesday)
From: MBrown.PA
Subject: Re: Design for Alpine online backup
In-reply-to: Taft's message of 20 Oct. 1981 3:42 pm PDT (Tuesday)
To: Taft
cc: MBrown, Kolling

Will files in a backup file system have the same IDs as on the original?  Or will there be a separate map from [volumeID, fileID] to fileID in a backup file system?  If not, we need lots of confidence in the uniqueness of file IDs on volumes connected to the backup system.

How will we treat immutable files (recall that the copies may have different owners and access control)?  It would seem that multiple copies are required; this impacts the first question.  Also, the LastBackupLogID of an immutable must be updated by the backup process.

Can we handle backup of workstation file systems this way?  Sounds plausible, but where is the information stored that tells what "backup server" to  interrogate to restore a particular file on a workstation FileStore?  On the failed workstation?  I can imagine other problems, too, since the backup system represents "free" disk quota for users (who use it to simulate a short-term archiving system.)

	--mark
*start*
01518 00024 US 
Date: 21 Oct. 1981 10:05 am PDT (Wednesday)
From: Taft.PA
Subject: Re: Design for Alpine online backup
In-reply-to: MBrown's message of 20-Oct-81 17:39:47 PDT (Tuesday)
To: MBrown
cc: Taft, Kolling

Hmmm, good questions.

1. It would appear that we need to have a separate [volumeID, fileID] -> fileID
map in the backup system, as you suggested.  In addition to the reasons you
mentioned, there are at least two other reasons for having such a map.  It is
needed if we are to back up multiple primary volumes onto a single backup set,
since otherwise there is no way to tell which files were on which volume. 
(Well, that's not strictly true: my proposed file map snapshot would give this
information also.)  And it enables us to treat the backup set as a write once-only
medium (until it is re-used), which eliminates the need to do logging while
doing backup, and makes it possible to use tapes, optical disks, etc., as the
backup medium.

2. Immutable files: it would seem that the LastBackupLogID can't be in the leader
page, or else a file's immutable attribute will have to be subverted in order to
change it.  (I believe such subversion is relatively easy.)  Having multiple
copies of an immutable file in a single file system seems an unlikely enough
case that it's not worth optimizing out the multiple backups.

3. I'm inclined to use this backup mechanism only for file servers; workstation
file systems will back themselves onto file servers using quite a different
mechanism.
	Ed

*start*
02416 00024 US 
Date: 21 Oct. 1981 4:58 pm PDT (Wednesday)
From: Kolling.PA
Subject: a thorn
To: mbrown
cc: Kolling, taft

You may remember the problem Ed pointed out awhile back, about
CheckAccessFile.  Namely that AF.Open would call AC.CheckAccessFile, which
would try to do an Open to read the file properties, which would.... and that you
suggested the solution of Open genning up a pseudo-"openFileHandle" before the
call on CheckAccessFile.

There are a couple of other places an AC that do Opens (on the owner database
file) and that I initially thought might wind up with a routine in the Monitor
eventually causing another call on the Monitor or something equally horrid.  As
luck would have it, they don't, if I have a separate monitor protecting the access
cache and if CheckAccessFile never causes anything to touch the rest of the
AccessControl database.  But this "luck" makes me nervous.  I would feel better
if I had a backdoor call on Open that guaranteed it wouldn't call AccessControl. 
Then I would know that I made no calls from AC to outside procedures that
called AC again.  I would only be calling read/write pages and
readfileproperties.  It would also remove the need for the hack in regular Open
and remove the need for the extra monitor, although Open would be less
efficient?  (I'm still kneading the AC code around, so there may be a simpler
solution to this after I've looked at it awhile.....)  Alternatively I could flag
CheckAccessFile with a big warning that it must be very stealthy and always
avoid various conflicts because of being called in this recursive fashion (yuk). 
Comments?

Just for random info, here are the baddies:

1. The procedure to register (and perhaps initialize) a volume group:  This will
  call Open for the owner database, which will call CheckAccessFile,
  which fortunately doesn't itself or anything it calls look
  at the volume group (or it would promptly ERROR UnregisteredVolumeGroup.)

2. The first time AC touches the owner database for a given transaction, down in
  the depths of the monitor it will try to Open it (If I don't protect this Open by
  the monitor, more than one process for the transaction might try to do it "at
  once".)  This Open will call CheckAccessFile.  As it is currently coded,
  CheckAccessFile gets into the monitor to update the little access cache.  Avoid
  this by two monitors and being careful.

Karen

*start*
00724 00024 US 
Date: 22 Oct. 1981 9:31 am PDT (Thursday)
From: Taft.PA
Subject: Re: a thorn
In-reply-to: Kolling's message of 21 Oct. 1981 4:58 pm PDT (Wednesday)
To: Kolling
cc: mbrown, taft

I believe all problems involving recursive Open/CheckAccessFile can easily be
circumvented.  Observe that the client of the recursive call is always
AccessControl, not AccessControl's client, and that AccessControl makes this call
as an enabled AlpineWheel.  So long as AccessControl checks the caller's
AlpineWheel status outside its own monitor (before doing anything else), there is
no problem with recursive entries into monitors.

I believe this observation applies to the other two cases you mentioned as well.
	Ed

*start*
00707 00024 US 
Date: 22 Oct. 1981 11:12 am PDT (Thursday)
From: Kolling.PA
Subject: Re: a thorn
In-reply-to: Taft's message of 22 Oct. 1981 9:31 am PDT (Thursday)
To: Taft
cc: Kolling, mbrown

There are two problems.  One is the infinite recursion on Open/CheckAccessFile
if CheckAccessFile has to Open the client's file to read its file properties.  This is
avoided by Mark's fix.  The problem with AC Opening the owner database can
indeed be avoided if CheckAccessFile always checks AlpineWheels first and
doesn't make any access cache entries for AlpineWheels and I flag the code to
warn future people.  (I was checking AlpineWheels last in my checking routines
for efficiency reasons.)

Karen

*start*
02304 00024 US 
Date: 23 Oct. 1981 4:26 pm PDT (Friday)
From: Taft.PA
Subject: OpenFileHandle
To: MBrown, Kolling
cc: Taft

I propose to change all present occurrences of OpenFileHandle in the public
interfaces to OpenFileID.  This is to be consistent with the following usage
convention which seems to be evolving:

	a Handle is a REF to some object;

	an ID is an uninterpreted string of bits identifying an object.

The OpenFileID that we hand to clients is clearly in the latter class (though
there is nothing wrong with the implementor using the bits of the ID to encode
information).

Along with this, I propose to restructure OpenFileMap in the following way. 
There will now be two exported types: OpenFileMap.ID (= OpenFileID) and
OpenFileMap.Handle (which is a REF to an OpenFileMap.Object).  There is only
one operation that deals with OpenFileMap.IDs:

OpenFileMap.GetHandle: PROC [Conversation, ID] RETURNS [Handle];

In addition to locating and returning the Handle, this procedure performs the
operations formerly specified for Validate.  All other operations in OpenFileMap,
and all operations in other internal interfaces, specify an open file by a Handle,
not an ID.

What I hope to accomplish by this is to make the AlpineFile.Close operation
"safe" in the face of multiple clients operating on the same open file
simultaneously.  In particular, I don't want a Handle to become invalid in the
middle of one client's operation because some other client asynchronously closed
it.

One way to implement this is for OpenFileMap to keep a table of Handles; some
bits of the ID are simply an index into this table.  Close simply sets the table
entry to NIL, so future calls to GetHandle will fail; however, other in-progress
calls may already have Handles referring to the open file object, so the object
will not disappear until all those calls have completed.  (If there is any cleanup
activity that is required when the object finally disappears, the garbage
collector's "finalization" mechanism can be used.)

This organization does have two consequences for internal clients of
OpenFileMap:

1) A remote caller's OpenFileID must be converted to a Handle upon each call,
and that Handle must be retained for the entire call;

2) Handles must not be retained between calls.

	Ed

*start*
02226 00024 US 
Date: 27-Oct-81 10:38:37 PST (Tuesday)
From: MBrown.PA
Subject: "Compound action" problem
To: Kolling, Taft
cc: MBrown

Consider a client of the AlpineFile interface, such as the Owner database.  A client action, such as "change space used for owner Foo under transaction t", is implemented as a sequence of AlpineFile calls under transaction t.  Between any two calls it is possible for the worker on this machine to receive the "Prepare to commit" command from the coordinator of transaction t.  It is reasonable (in my opinion) to treat such a prepare call as an error, and abort the transaction, but first the condition must be detected and communicated to the worker.

Only the client can define these "sub-transactions"; they are application-dependent.  There seem to be two possible designs:

(1) all responsibility lies with the client.  The client registers as a cache manager for transaction t, and therefore is called by Prepare.  The client detects the problem at this time and makes a failure return to Prepare, which aborts the transaction.

With this approach, a client must maintain a data structure of transactions in progress.  (Many clients will already have such a data structure.)

(2) the system supports a new notion: the "client action", with calls BeginClientAction[t: transaction] -> clientAction, and EndClientAction[c: clientAction].  By bracketing a sequence of calls with BeginClientAction and EndClientAction, an client ensures that either all of the calls will complete, or the transaction will abort.

With this approach, the system attaches a new data structure to the worker object to represent client actions in progress.


At first I preferred approach (1), but now I like (2).  The reason is that I would like to have this degree of safety without forcing the client to register as a (possibly remote) cache manager.  In many cases I expect clients to arrange their own protocol for cleaning things up for commit, and as long as these client protocols work the entire issue is moot, but I want extra redundancy.  (Since solution 1 is free to implement, there is no reason not to have it, too.)

Karen, how is the Owner database handling this problem now?

	--mark
*start*
00900 00024 US 
Date: 27-Oct-81 17:29:51 PST (Tuesday)
From: MBrown.PA
Subject: Re: Talking to many servers
In-reply-to: Birrell's message of 26 Oct. 1981 9:34 am PST (Monday)
To: Birrell
cc: MBrown, Taft, Kolling, Nelson, Boggs, Swinehart

I am plunging ahead with an implementation of the transaction algorithm, based on your proposal.  I think that it will all work out, but I am also becoming convinced that RPC is now complicated enough to discourage many clients.  I think that the global frames of client stubs should be more fully hidden.  This means lumping Replicate and Import together into one operation, and having this operation return a collectible "interface record" that has finalization established.  If the performance is poor, due to the module NEWs and UNNEWs expended in failed binding attempts, then caching of client stub global frames should be implemented.

	--mark
*start*
01747 00024 US 
Date: 29 Oct. 1981 3:03 pm PST (Thursday)
From: Nelson.PA
Subject: RPC.mesa, CedarRPC.mesa, binding, and more
To: Birrell, MBrown, Taft
cc: Kolling, Swinehart, Nelson

As a consequence of the "best" solution to Mark's multiple instance problem, it is
necessary for Lupine to distinguish Cedar interfaces from nonCedar interfaces. 
This was something that I hoped to ignore, but is now impossible.

As a result, several things improve:  

Old CedarRPC changes drastically.  The new one is a Cedar image of RPC.mesa,
which means that Alpine code should use only CedarRpc, never RPC, for all
uses--types, authentication routines, signals, and so on.  My personal approach
would be to IMPORT RPC: CedarRPC in every rpc-using module.

All binding is done direcly through the RpcControl modules, not thru the
defunct CedarRPC veneer, since they now understand Cedar when
TargetLanguage[Cedar] is specified at translation time (the default).

Both RPC interfaces now have a Zones record for parameter storage zones, as
discussed in a previous msg.  Any existing code using CedarRpc or XXRpcControl
will have to change a bit.

Because of the two dual interfaces, generating conditional stubs is not too
terrible, and some parts are cleaner.

Updated versions of RPC and CedarRPC--if you need them now--can be found
on [Ivy]<Nelson>Lupine>Temp> (.mesa and .bcd).  The latest Lupine generates
stubs using these interfaces, and the stubs compile correctly.  But the multiple
instance stuff for Mark is not there yet; it will be several more days.

I have or will give you hardcopy of the new interfaces.  Please report your
impressions with Andrew so that he can adapt/adopt these interfaces into
RpcRuntime.df ASAP.

							Bruce

*start*
01977 00024 US 
Date: 19 Nov. 1981 9:12 am PST (Thursday)
From: Birrell.pa
Subject: Re: New RNames
In-reply-to: Your message of 18-Nov-81 17:05:20 PST (Wednesday)
To: MBrown
cc: CedarRPC↑, Schroeder, Birrell

I've created an "Alpine" registry, and the individuals Mark requested:

	Carson.alpine
	Ebbetts.alpine
	Luther.alpine
	Monitor.alpine

The "friends" of the Alpine registry are CedarRPC↑.pa.  The passwords for the
individuals I created are initially null, so you can't log in as those individuals. 
The friends of the registry can change the individuals' passwords to a non-null
value if desired; "real" passwords should be at least 8 characters and
unpronouncable.  The friends of the registry can also adjust individuals'
connect-sites, although that shouldn't be necessary.  The individuals have no
mailboxes, so they can't receive mail.

To export an RPC interface whose instance name is one of these individuals, you
must provide sufficient credentials to be allowed to update the "connect-site"
field of the individual's database entry.  Suitable credentials are either the
individual's name and non-null password, or the name and password of a friend
of the registry.

The instance name of an RPC export/import may also be an NLS name string
(like "Indigo") or a Pup host address constant (like "3#44#").

It is acceptable to have exports with different type names but the same instance
name iff the exports are on the same host.

The "production" usage of these names that I envisage is that each name
corresponds to an alpine server.  Each Alpine server must know its own name
and password.  Then when exporting an interface, the server uses its own
credentials.  This may be the best way to proceed in debugging experiments, too.

Please don't do anything to the registry if you aren't sure of what you're doing. 
Consult Mike or me if in doubt.  It may be worth (re-)reading the grapevine
paper and/or the grapevine interface specification.

Andrew

*start*
00605 00024 US 
Date: 20 Nov. 1981 9:17 am PST (Friday)
From: Nelson.PA
Subject: A bit more on Duplicate Export Problems
To: Sturgis, CedarRPC↑
Reply-To: Nelson

I forgot to say that the following may also work.  The idea is to get the binder to
assign an unused name to the remote TransMgr interface, so that it will never
conflict with the local one (which continues to be called TransMgr).

Alpine: CONFIG =
  BEGIN
  AlpineImpl;
  RpcRuntime;
  [ignoreMe: TransMgr, TransMgrRpcControl: TransMgrRpcControl] ←
    TransMgrRpcClientImpl[];
  END;

I have not tried this.  No Mesa in my office!


*start*
01109 00024 US 
Date: 18-Dec-81 19:05:07 PST (Friday)
From: Kolling.PA
Subject: questions about errors
To: mbrown
cc: Kolling

Consider two types of errors I can get from my calls to AlpineFile for operations on the owner files:

1. something that indicates a system logic error (AccessFailed, etc.)

2. file not reachable due to volume going offline.  note that this is not the same as my having been told that a volume is unregistered, rather this is a volume going offline behind my back.

It is my belief that if an error of type #1 happens, I should cause an error fatal to the system, without releasing buffers, etc. because I may want to look at them during debugging.  Yes?  No?

It is my belief that if an error of type #2 happens, I should gently back out and tell the caller ERROR VolumeOffline or some such.  Yes?  No?

I don't see any definition in AlpineFile for errors of type #2.....

Should I put ANY catches on my calls to AlpineFile, and consider any errors I don't recognize as class #1, class #2, or otherwise acceptable (lock timeout, etc.) as being fatal to the system?

Karen