00001 // Copyright (C) 2001, Compaq Computer Corporation 00002 // 00003 // This file is part of Vesta. 00004 // 00005 // Vesta is free software; you can redistribute it and/or 00006 // modify it under the terms of the GNU Lesser General Public 00007 // License as published by the Free Software Foundation; either 00008 // version 2.1 of the License, or (at your option) any later version. 00009 // 00010 // Vesta is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 // Lesser General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU Lesser General Public 00016 // License along with Vesta; if not, write to the Free Software 00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00018 00019 // 00020 // VestaSourceAtomic.H 00021 // Last modified on Wed Feb 23 20:06:06 EST 2005 by ken@xorian.net 00022 // modified on Fri Nov 10 12:11:54 PST 2000 by mann 00023 // 00024 00025 // Facility for grouping several VestaSource actions into an atomic 00026 // unit, from outside the repository address space. The interface 00027 // essentially lets you write a short, straight-line program in a very 00028 // restricted language and ship it to the repository, where it is 00029 // executed atomically. 00030 00031 // A program is a sequence of steps. A newly created 00032 // VestaSourceAtomic object represents an empty program; invoking 00033 // methods on this object appends steps to the program. After the 00034 // program is completely entered, it can either be run by invoking the 00035 // run() method, or be cancelled by using the cancel() method or 00036 // deleting the object. A program can be run at most once. Programs 00037 // that have not yet been run or cancelled consume resources on the 00038 // repository server. 00039 00040 // A program's state consists of a list of VestaSource objects, two 00041 // current target error codes, and an ok-replacement error code. The 00042 // list of objects is initially empty, and the three error codes are 00043 // all initially VestaSource::ok. A step can either append a given 00044 // VestaSource to the list, change the target and ok-replacement error 00045 // codes, or select a VestaSource from the list by index number and 00046 // invoke one of its methods. If such a method invocation returns a 00047 // new VestaSource object, the new object is appended to the list. 00048 // Every step is executed with the privileges of the same user, as 00049 // specified in the VestaSourceAtomic constructor. 00050 00051 // Unless otherwise noted below, the execution of each step generates 00052 // a VestaSource::errorCode that is tested against the targets. If it 00053 // matches either target, the program continues; if not, it halts. 00054 // When a program halts due to missing the error code target, no 00055 // further steps are executed, but any preceding steps that had side 00056 // effects ARE STILL COMMITTED; there is no voluntary abort and 00057 // roll-back feature. When the program halts or ends normally, the 00058 // number of steps successfully completed is available in the ndone 00059 // field, the VestaSource::errorCode returned by the last step is 00060 // available in the lasterr field, and the ok-replacement error code 00061 // after the last step is available in the okreplace field. 00062 00063 // A common use for the target and ok-replacement error codes is to 00064 // check that a given name does *not* exist, by doing a lookup() with 00065 // both targets set to VestaSource::notFound and the ok-replacement set 00066 // to VestaSource::nameInUse. 00067 00068 // Defaulting the timestamp argument in a step (i.e., setting it to 0) 00069 // is handled specially. For each atomic program, the repository 00070 // server reads the system clock once (after the write lock is 00071 // acquired) and uses the resulting time for all steps where the 00072 // timestamp argument is defaulted. 00073 00074 // Program execution is atomic in the following sense: First, the 00075 // repository write lock is held during execution, so no client can 00076 // see intermediate states between steps. Second, the repository's 00077 // atomic logging mechanism ensures that neither a repository crash 00078 // nor a client crash can cause the program to halt and commit; the 00079 // program either runs as if there had not been a crash, or aborts and 00080 // makes no change to the repository. 00081 00082 // Each step method accepts a stepname argument. These names are 00083 // accumulated into a sequence and can be retrieved using the name() 00084 // method. This feature is intended for use in error message 00085 // printing; for example: 00086 // 00087 // if (!vsa.run()) { 00088 // VestaSource::errorCode err = 00089 // (vsa.lasterr == VestaSource::ok) ? vsa.okeplace : vsa.lasterr; 00090 // cerr << program_name << ": " << vsa.name(vsa.ndone) << ": " 00091 // << ReposUI::errorCodeText(err) << endl; 00092 // exit(1); 00093 // } 00094 // 00095 // For uniformity, all step types take a stepname argument, even those 00096 // that cannot cause an error. The repos_ui tools generally supply 00097 // the full pathname of the VestaSource object being operated on as 00098 // the stepname, but other ways of naming steps could make sense too. 00099 // Printing vsa.ndone itself in the error message can be useful when 00100 // debugging. 00101 00102 // The methods of this interface are not monitored, and should not be 00103 // called concurrently on the same VestaSourceAtomic object. The 00104 // client is responsible for any locking needed to ensure this. 00105 00106 #ifndef _VSA_H 00107 #define _VSA_H 1 00108 00109 #include "Basics.H" 00110 #include "FP.H" 00111 #include "SRPC.H" 00112 #include "MultiSRPC.H" 00113 #include "AccessControl.H" 00114 #include "VestaSource.H" 00115 #include "Sequence.H" 00116 00117 class VestaSourceAtomic { 00118 public: 00119 // 00120 // Types 00121 // 00122 typedef int VSIndex; 00123 00124 // 00125 // Data fields. These are all read-only for the client! 00126 // 00127 00128 // Counts the number of steps entered so far. 00129 int nsteps; 00130 // Counts the number of VestaSource objects on the list. 00131 VSIndex nobjects; 00132 // Remembers the current target error codes. 00133 VestaSource::errorCode target1, target2; 00134 00135 // Returns the number of steps successfully executed. 00136 int ndone; 00137 // Returns the error code from the last step attempted. 00138 VestaSource::errorCode lasterr; 00139 // Returns the ok-replacement error code from the last step attempted. 00140 VestaSource::errorCode okreplace; 00141 00142 // 00143 // Constructors and destructor 00144 // 00145 00146 // Use the default repository 00147 VestaSourceAtomic(AccessControl::Identity who =NULL) throw (SRPC::failure); 00148 00149 // Specify the repository by host and port 00150 VestaSourceAtomic(const Text& host, const Text& port, 00151 AccessControl::Identity who =NULL) throw (SRPC::failure); 00152 00153 // Free resources consumed by the program 00154 ~VestaSourceAtomic() throw (); 00155 00156 // 00157 // Add steps to the program. Where no comments are provided, the 00158 // step invokes a VestaSource method of the same name in the obvious 00159 // way; see VestaSource.H and the general description above. 00160 // 00161 00162 // Set the target and ok-replacement error codes. Generates no 00163 // error code of its own. 00164 void setTarget(const Text& stepname, 00165 VestaSource::errorCode target1 =VestaSource::ok, 00166 VestaSource::errorCode target2 =VestaSource::ok, 00167 VestaSource::errorCode okreplace =VestaSource::ok 00168 ) throw (SRPC::failure); 00169 00170 // Add a VestaSource to the list and return its index number. If 00171 // vs->longid proves to be invalid at runtime, NULL is added to the 00172 // list and the error code is VestaSource::notFound; otherwise the 00173 // error code is VestaSource::ok. 00174 VSIndex decl(const Text& stepname, VestaSource* vs) throw (SRPC::failure); 00175 00176 // Call resync at the server. Always generates VestaSource::ok. 00177 void resync(const Text& stepname, VSIndex vsi) throw (SRPC::failure); 00178 00179 void setTimestamp(const Text& stepname, VSIndex vsi, time_t ts) 00180 throw (SRPC::failure); 00181 00182 VSIndex lookup(const Text& stepname, VSIndex vsi, const Text& arc) 00183 throw (SRPC::failure); 00184 00185 VSIndex lookupPathname(const Text& stepname, 00186 VSIndex vsi, const Text& pathname, 00187 char pathnameSep =PathnameSep) throw (SRPC::failure); 00188 00189 VSIndex lookupIndex(const Text& stepname, 00190 VSIndex vsi, unsigned int index) throw (SRPC::failure); 00191 00192 void reallyDelete(const Text& stepname, 00193 VSIndex vsi, const Text& arc, bool existCheck =true, 00194 time_t timestamp =0) throw (SRPC::failure); 00195 00196 VSIndex insertFile(const Text& stepname, 00197 VSIndex vsi, const Text& arc, ShortId sid, bool master, 00198 VestaSource::dupeCheck chk =VestaSource::dontReplace, 00199 time_t timestamp =0, FP::Tag* fptag =NULL 00200 ) throw (SRPC::failure); 00201 00202 VSIndex insertMutableFile(const Text& stepname, 00203 VSIndex vsi, const Text& arc, ShortId sid, bool master, 00204 VestaSource::dupeCheck chk 00205 =VestaSource::dontReplace, 00206 time_t timestamp =0, FP::Tag* fptag =NULL 00207 ) throw (SRPC::failure); 00208 00209 // If dir is to be NULL in the method, use -1 as diri. 00210 VSIndex insertImmutableDirectory(const Text& stepname, VSIndex parenti, 00211 const Text& arc, VSIndex diri, bool master, 00212 VestaSource::dupeCheck chk 00213 =VestaSource::dontReplace, 00214 time_t timestamp =0, 00215 FP::Tag* fptag =NULL) throw (SRPC::failure); 00216 00217 VSIndex insertAppendableDirectory(const Text& stepname, 00218 VSIndex vsi, const Text& arc, bool master, 00219 VestaSource::dupeCheck chk 00220 =VestaSource::dontReplace, 00221 time_t timestamp =0) throw (SRPC::failure); 00222 00223 // If dir is to be NULL in the method, use -1 as diri. 00224 VSIndex insertMutableDirectory(const Text& stepname, VSIndex parenti, 00225 const Text& arc, VSIndex diri, bool master, 00226 VestaSource::dupeCheck chk 00227 =VestaSource::dontReplace, 00228 time_t timestamp =0) throw (SRPC::failure); 00229 00230 VSIndex insertGhost(const Text& stepname, VSIndex vsi, 00231 const Text& arc, bool master, 00232 VestaSource::dupeCheck chk =VestaSource::dontReplace, 00233 time_t timestamp =0) throw (SRPC::failure); 00234 00235 VSIndex insertStub(const Text& stepname, VSIndex vsi, 00236 const Text& arc, bool master, 00237 VestaSource::dupeCheck chk =VestaSource::dontReplace, 00238 time_t timestamp =0) throw (SRPC::failure); 00239 00240 void renameTo(const Text& stepname, 00241 VSIndex vsi, const Text& arc, 00242 VSIndex fromDirI, const Text& fromArc, 00243 VestaSource::dupeCheck chk =VestaSource::dontReplace, 00244 time_t timestamp =0) throw (SRPC::failure); 00245 00246 void makeFilesImmutable(const Text& stepname, VSIndex vsi, 00247 unsigned int threshold) throw (SRPC::failure); 00248 00249 // For error code checking, a true return (vs->master == master) 00250 // generates VestaSource::ok; a false return generates the err argument. 00251 void testMaster(const Text& stepname, VSIndex vsi, bool master, 00252 VestaSource::errorCode err) throw (SRPC::failure); 00253 00254 void setMaster(const Text& stepname, VSIndex vsi, bool state) 00255 throw (SRPC::failure); 00256 00257 // For error code checking, inAttribs == expected generates 00258 // VestaSource::ok; inAttribs != expected generates the err argument. 00259 void inAttribs(const Text& stepname, 00260 VSIndex vsi, const Text& name, const Text& value, 00261 bool expected, VestaSource::errorCode err) 00262 throw (SRPC::failure); 00263 00264 inline void setAttrib(const Text& stepname, 00265 VSIndex vsi, const Text& name, const Text& value, 00266 time_t timestamp =0) throw (SRPC::failure) 00267 { writeAttrib(stepname, vsi, VestaSource::opSet, name, value, 00268 timestamp); }; 00269 00270 inline void clearAttrib(const Text& stepname, VSIndex vsi, const Text& name, 00271 time_t timestamp =0) throw (SRPC::failure) 00272 { writeAttrib(stepname, vsi, VestaSource::opClear, name, "", timestamp); }; 00273 00274 inline void addAttrib(const Text& stepname, 00275 VSIndex vsi, const Text& name, const Text& value, 00276 time_t timestamp =0) throw (SRPC::failure) 00277 { writeAttrib(stepname, vsi, VestaSource::opAdd, name, value, timestamp); } 00278 00279 inline void removeAttrib(const Text& stepname, 00280 VSIndex vsi, const Text& name, const Text& value, 00281 time_t timestamp =0) throw (SRPC::failure) 00282 { writeAttrib(stepname, vsi, VestaSource::opRemove, name, value, 00283 timestamp); }; 00284 00285 void writeAttrib(const Text& stepname, VSIndex vsi, VestaSource::attribOp op, 00286 const Text& name, const Text& value, 00287 time_t timestamp =0) throw (SRPC::failure); 00288 00289 // Merge the value(s) of attribute "name" from fromvsi into tovsi. 00290 // If name is NULL or "", all attributes of fromvsi are merged in. 00291 void mergeAttrib(const Text& stepname, VSIndex fromvsi, VSIndex tovsi, 00292 const Text& name, time_t timestamp =0) 00293 throw (SRPC::failure); 00294 00295 // Invoke AccessControl::check on vsi's ac field. For error code 00296 // checking, check == expected generates VestaSource::ok; 00297 // check != expected generates the err argument. 00298 void accessCheck(const Text& stepname, 00299 VSIndex vsi, AccessControl::Class cls, bool expected, 00300 VestaSource::errorCode err) throw (SRPC::failure); 00301 00302 // Compare vsi's type field to a bitmap of allowed value(s). Let 00303 // tbit = 1 << (int) type(vsi). Then if (tbit & allowed) == 0, this 00304 // step generates err; otherwise it generates VestaSource::ok. 00305 static inline unsigned int typebit(VestaSource::typeTag type) { 00306 return 1 << ((int) type); 00307 }; 00308 void typeCheck(const Text& stepname, 00309 VSIndex vsi, unsigned int allowed, 00310 VestaSource::errorCode err) throw (SRPC::failure); 00311 00312 // 00313 // Run the program. Returns true if all steps were successfully 00314 // executed. The number of steps successfully executed and the 00315 // error code value from the last step attempted are placed in the 00316 // ndone and lasterr fields of the object, respectively. The 00317 // resources associated with the program are freed and it cannot be 00318 // executed again. 00319 // 00320 bool run() throw (SRPC::failure); 00321 00322 // 00323 // Choose not to run the program. The resources associated with the 00324 // program are freed and it cannot be executed again. Called 00325 // automatically by the destructor if run() has not yet been called. 00326 // 00327 void cancel() throw (SRPC::failure); 00328 00329 // 00330 // Obtain the name of the nth step (0-origin). 00331 // 00332 Text name(int step) throw (); 00333 00334 // 00335 // Private stuff 00336 // 00337 private: 00338 SRPC* srpc; 00339 MultiSRPC::ConnId id; 00340 typedef Sequence<Text> NameSeq; 00341 NameSeq* names; 00342 }; 00343 00344 #endif // _VSA_H