1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1997,2008 Oracle. All rights reserved. 5 * 6 * $Id: LockExample.cpp,v 12.6 2008/01/08 20:58:26 bostic Exp $ 7 */ 8 9#include <sys/types.h> 10 11#include <errno.h> 12#include <iostream> 13#include <stdlib.h> 14#include <string.h> 15 16#include <db_cxx.h> 17 18using std::cin; 19using std::cout; 20using std::cerr; 21 22const char *progname = "LockExample"; // Program name. 23 24// 25// An example of a program using DBLock and related classes. 26// 27class LockExample : public DbEnv 28{ 29public: 30 void run(); 31 int error_code() { return (ecode); } 32 33 LockExample(const char *home, u_int32_t maxlocks, int do_unlink); 34 35private: 36 static const char FileName[]; 37 int ecode; 38 39 // no need for copy and assignment 40 LockExample(const LockExample &); 41 void operator = (const LockExample &); 42}; 43 44static int usage(); // forward 45 46int 47main(int argc, char *argv[]) 48{ 49 const char *home; 50 int do_unlink; 51 u_int32_t maxlocks; 52 int i; 53 54 home = "TESTDIR"; 55 maxlocks = 0; 56 do_unlink = 0; 57 for (int argnum = 1; argnum < argc; ++argnum) { 58 if (strcmp(argv[argnum], "-h") == 0) { 59 if (++argnum >= argc) 60 return (usage()); 61 home = argv[argnum]; 62 } 63 else if (strcmp(argv[argnum], "-m") == 0) { 64 if (++argnum >= argc) 65 return (usage()); 66 if ((i = atoi(argv[argnum])) <= 0) 67 return (usage()); 68 maxlocks = (u_int32_t)i; /* XXX: possible overflow. */ 69 } 70 else if (strcmp(argv[argnum], "-u") == 0) { 71 do_unlink = 1; 72 } 73 else { 74 return (usage()); 75 } 76 } 77 78 try { 79 int ecode; 80 81 if (do_unlink) { 82 // Create an environment that immediately 83 // removes all files. 84 LockExample tmp(home, maxlocks, do_unlink); 85 if ((ecode = tmp.error_code()) != 0) 86 return (ecode); 87 } 88 89 LockExample app(home, maxlocks, do_unlink); 90 if ((ecode = app.error_code()) != 0) 91 return (ecode); 92 app.run(); 93 app.close(0); 94 return (EXIT_SUCCESS); 95 } 96 catch (DbException &dbe) { 97 cerr << "LockExample: " << dbe.what() << "\n"; 98 return (EXIT_FAILURE); 99 } 100} 101 102LockExample::LockExample(const char *home, u_int32_t maxlocks, int do_unlink) 103: DbEnv(0) 104, ecode(0) 105{ 106 int ret; 107 108 if (do_unlink) { 109 if ((ret = remove(home, DB_FORCE)) != 0) { 110 cerr << progname << ": DbEnv::remove: " 111 << strerror(errno) << "\n"; 112 ecode = EXIT_FAILURE; 113 } 114 } 115 else { 116 set_error_stream(&cerr); 117 set_errpfx("LockExample"); 118 if (maxlocks != 0) 119 set_lk_max_locks(maxlocks); 120 open(home, DB_CREATE | DB_INIT_LOCK, 0); 121 } 122} 123 124void LockExample::run() 125{ 126 long held; 127 size_t len; 128 u_int32_t locker; 129 int did_get, ret; 130 DbLock *locks = 0; 131 int lockcount = 0; 132 int lockid = 0; 133 char objbuf[1024]; 134 135 // 136 // Accept lock requests. 137 // 138 lock_id(&locker); 139 for (held = 0;;) { 140 cout << "Operation get/release [get]> "; 141 cout.flush(); 142 143 char opbuf[16]; 144 cin.getline(opbuf, sizeof(opbuf)); 145 if (cin.eof()) 146 break; 147 if ((len = strlen(opbuf)) <= 1 || strcmp(opbuf, "get") == 0) { 148 // Acquire a lock. 149 cout << "input object (text string) to lock> "; 150 cout.flush(); 151 cin.getline(objbuf, sizeof(objbuf)); 152 if (cin.eof()) 153 break; 154 if ((len = strlen(objbuf)) <= 0) 155 continue; 156 157 char lockbuf[16]; 158 do { 159 cout << "lock type read/write [read]> "; 160 cout.flush(); 161 cin.getline(lockbuf, sizeof(lockbuf)); 162 if (cin.eof()) 163 break; 164 len = strlen(lockbuf); 165 } while (len >= 1 && 166 strcmp(lockbuf, "read") != 0 && 167 strcmp(lockbuf, "write") != 0); 168 169 db_lockmode_t lock_type; 170 if (len <= 1 || strcmp(lockbuf, "read") == 0) 171 lock_type = DB_LOCK_READ; 172 else 173 lock_type = DB_LOCK_WRITE; 174 175 Dbt dbt(objbuf, (u_int32_t)strlen(objbuf)); 176 177 DbLock lock; 178 ret = lock_get(locker, DB_LOCK_NOWAIT, &dbt, 179 lock_type, &lock); 180 did_get = 1; 181 lockid = lockcount++; 182 if (locks == NULL) { 183 locks = new DbLock[1]; 184 } 185 else { 186 DbLock *newlocks = new DbLock[lockcount]; 187 for (int lockno = 0; 188 lockno < lockid; lockno++) { 189 newlocks[lockno] = locks[lockno]; 190 } 191 delete locks; 192 locks = newlocks; 193 } 194 locks[lockid] = lock; 195 } else { 196 // Release a lock. 197 do { 198 cout << "input lock to release> "; 199 cout.flush(); 200 cin.getline(objbuf, sizeof(objbuf)); 201 if (cin.eof()) 202 break; 203 } while ((len = strlen(objbuf)) <= 0); 204 lockid = strtol(objbuf, NULL, 16); 205 if (lockid < 0 || lockid >= lockcount) { 206 cout << "Lock #" << lockid << " out of range\n"; 207 continue; 208 } 209 DbLock lock = locks[lockid]; 210 ret = lock_put(&lock); 211 did_get = 0; 212 } 213 214 switch (ret) { 215 case 0: 216 cout << "Lock #" << lockid << " " 217 << (did_get ? "granted" : "released") 218 << "\n"; 219 held += did_get ? 1 : -1; 220 break; 221 case DB_LOCK_NOTGRANTED: 222 cout << "Lock not granted\n"; 223 break; 224 case DB_LOCK_DEADLOCK: 225 cerr << "LockExample: lock_" 226 << (did_get ? "get" : "put") 227 << ": " << "returned DEADLOCK"; 228 break; 229 default: 230 cerr << "LockExample: lock_get: %s", 231 strerror(errno); 232 } 233 } 234 cout << "\n"; 235 cout << "Closing lock region " << held << " locks held\n"; 236 if (locks != 0) 237 delete locks; 238} 239 240static int 241usage() 242{ 243 cerr << "usage: LockExample [-u] [-h home] [-m maxlocks]\n"; 244 return (EXIT_FAILURE); 245} 246