Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Reorganize the proxy-locking method in os_unix.c. Additional cleanup. (CVS 5971) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
31f6090e22b54d657afc8c23171d000d |
User & Date: | drh 2008-12-03 22:32:45.000 |
Context
2008-12-03
| ||
22:48 | Fix a missing forward declaration that is needed when SQLITE_PREFER_PROXY_LOCKING is defined. (CVS 5972) (check-in: 24235300b3 user: drh tags: trunk) | |
22:32 | Reorganize the proxy-locking method in os_unix.c. Additional cleanup. (CVS 5971) (check-in: 31f6090e22 user: drh tags: trunk) | |
21:26 | Make os_unix compile with SQLITE_ENABLE_PROXY_LOCKING (CVS 5970) (check-in: 3efedac6aa user: aswift tags: trunk) | |
Changes
Changes to src/os_unix.c.
︙ | ︙ | |||
24 25 26 27 28 29 30 | ** KEEP THE STRUCTURE OF THIS FILE INTACT. New code should be placed ** in the correct division and should be clearly labeled. ** ** The layout of divisions is as follows: ** ** * General-purpose declarations and utility functions. ** * Unique file ID logic used by VxWorks. | | < > | | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | ** KEEP THE STRUCTURE OF THIS FILE INTACT. New code should be placed ** in the correct division and should be clearly labeled. ** ** The layout of divisions is as follows: ** ** * General-purpose declarations and utility functions. ** * Unique file ID logic used by VxWorks. ** * Various locking primitive implementations (all except proxy locking): ** + for Posix Advisory Locks ** + for no-op locks ** + for dot-file locks ** + for flock() locking ** + for named semaphore locks (VxWorks only) ** + for AFP filesystem locks (MacOSX only) ** * sqlite3_file methods not associated with locking. ** * Definitions of sqlite3_io_methods objects for all locking ** methods plus "finder" functions for each locking method. ** * sqlite3_vfs method implementations. ** * Locking primitives for the proxy uber-locking-method. (MacOSX only) ** * Definitions of sqlite3_vfs objects for all locking methods ** plus implementations of sqlite3_os_init() and sqlite3_os_end(). ** ** $Id: os_unix.c,v 1.227 2008/12/03 22:32:45 drh Exp $ */ #include "sqliteInt.h" #if SQLITE_OS_UNIX /* This file is used on unix only */ /* ** There are various methods for file locking used for concurrency ** control: |
︙ | ︙ | |||
751 752 753 754 755 756 757 | ** runtime. On these latter systems, SQLTIE_THREAD_OVERRIDE_LOCK is ** undefined. ** ** This variable normally has file scope only. But during testing, we make ** it a global so that the test code can change its value in order to verify ** that the right stuff happens in either case. */ | > | | | | | > | 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 | ** runtime. On these latter systems, SQLTIE_THREAD_OVERRIDE_LOCK is ** undefined. ** ** This variable normally has file scope only. But during testing, we make ** it a global so that the test code can change its value in order to verify ** that the right stuff happens in either case. */ #if SQLITE_THREADSAFE && defined(__linux__) # ifndef SQLITE_THREAD_OVERRIDE_LOCK # define SQLITE_THREAD_OVERRIDE_LOCK -1 # endif # ifdef SQLITE_TEST int threadsOverrideEachOthersLocks = SQLITE_THREAD_OVERRIDE_LOCK; # else static int threadsOverrideEachOthersLocks = SQLITE_THREAD_OVERRIDE_LOCK; # endif #endif /* ** This structure holds information passed into individual test ** threads by the testThreadLockingBehavior() routine. */ struct threadTestData { |
︙ | ︙ | |||
820 821 822 823 824 825 826 | d.lock.l_type = F_WRLCK; pthread_create(&t, 0, threadLockingTest, &d); pthread_join(t, 0); close(fd); if( d.result!=0 ) return; threadsOverrideEachOthersLocks = (d.lock.l_type==F_UNLCK); } | < < < < < < < < | 822 823 824 825 826 827 828 829 830 831 832 833 834 835 | d.lock.l_type = F_WRLCK; pthread_create(&t, 0, threadLockingTest, &d); pthread_join(t, 0); close(fd); if( d.result!=0 ) return; threadsOverrideEachOthersLocks = (d.lock.l_type==F_UNLCK); } #endif /* SQLITE_THERADSAFE && defined(__linux__) */ /* ** Release a unixLockInfo structure previously allocated by findLockInfo(). */ static void releaseLockInfo(struct unixLockInfo *pLock){ if( pLock ){ |
︙ | ︙ | |||
2523 2524 2525 2526 2527 2528 2529 | sqlite3_free(pOpen->aPending); pOpen->nPending = 0; pOpen->aPending = 0; } } } } | < | 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 | sqlite3_free(pOpen->aPending); pOpen->nPending = 0; pOpen->aPending = 0; } } } } unixLeaveMutex(); if( rc==SQLITE_OK ) pFile->locktype = locktype; return rc; } /* ** Close a file & cleanup AFP specific locking context |
︙ | ︙ | |||
2571 2572 2573 2574 2575 2576 2577 | /* ** The code above is the AFP lock implementation. The code is specific ** to MacOSX and does not work on other unix platforms. No alternative ** is available. If you don't compile for a mac, then the "unix-afp" ** VFS is not available. ** ********************* End of the AFP lock implementation ********************** | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 | /* ** The code above is the AFP lock implementation. The code is specific ** to MacOSX and does not work on other unix platforms. No alternative ** is available. If you don't compile for a mac, then the "unix-afp" ** VFS is not available. ** ********************* End of the AFP lock implementation ********************** ******************************************************************************/ /****************************************************************************** **************** Non-locking sqlite3_file methods ***************************** ** ** The next division contains implementations for all methods of the |
︙ | ︙ | |||
3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 | */ if( *pSize==1 ) *pSize = 0; return SQLITE_OK; } /* ** Information and control of an open file handle. */ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ switch( op ){ case SQLITE_FCNTL_LOCKSTATE: { *(int*)pArg = ((unixFile*)id)->locktype; return SQLITE_OK; } case SQLITE_LAST_ERRNO: { *(int*)pArg = ((unixFile*)id)->lastErrno; return SQLITE_OK; } #if SQLITE_ENABLE_LOCKING_STYLE && defined(__DARWIN__) | > > > > > > < < < < < < < < < < < < < < < | < < < < < < < < < | < < < < < < < < < < < < < < < < < < < | | 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 | */ if( *pSize==1 ) *pSize = 0; return SQLITE_OK; } /* ** Handler for proxy-locking file-control verbs. Defined below in the ** proxying locking division. */ static int proxyFileControl(sqlite3_file*,int,void*); /* ** Information and control of an open file handle. */ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ switch( op ){ case SQLITE_FCNTL_LOCKSTATE: { *(int*)pArg = ((unixFile*)id)->locktype; return SQLITE_OK; } case SQLITE_LAST_ERRNO: { *(int*)pArg = ((unixFile*)id)->lastErrno; return SQLITE_OK; } #if SQLITE_ENABLE_LOCKING_STYLE && defined(__DARWIN__) case SQLITE_SET_LOCKPROXYFILE: case SQLITE_GET_LOCKPROXYFILE: { return proxyFileControl(id,op,pArg); } #endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__DARWIN__) */ } return SQLITE_ERROR; } /* |
︙ | ︙ | |||
4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 | afpIoFinder, /* Finder function name */ afpIoMethods, /* sqlite3_io_methods object name */ afpClose, /* xClose method */ afpLock, /* xLock method */ afpUnlock, /* xUnlock method */ afpCheckReservedLock /* xCheckReservedLock method */ ); IOMETHODS( proxyIoFinder, /* Finder function name */ proxyIoMethods, /* sqlite3_io_methods object name */ proxyClose, /* xClose method */ proxyLock, /* xLock method */ proxyUnlock, /* xUnlock method */ proxyCheckReservedLock /* xCheckReservedLock method */ | > > > > > > > > > > > > > > > > | 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 | afpIoFinder, /* Finder function name */ afpIoMethods, /* sqlite3_io_methods object name */ afpClose, /* xClose method */ afpLock, /* xLock method */ afpUnlock, /* xUnlock method */ afpCheckReservedLock /* xCheckReservedLock method */ ); #endif /* ** The proxy locking method is a "super-method" in the sense that it ** opens secondary file descriptors for the conch and lock files and ** it uses proxy, dot-file, AFP, and flock() locking methods on those ** secondary files. For this reason, the division that implements ** proxy locking is located much further down in the file. But we need ** to go ahead and define the sqlite3_io_methods and finder function ** for proxy locking here. So we forward declare the I/O methods. */ #if defined(__DARWIN__) && SQLITE_ENABLE_LOCKING_STYLE static int proxyClose(sqlite3_file*); static int proxyLock(sqlite3_file*, int); static int proxyUnlock(sqlite3_file*, int); static int proxyCheckReservedLock(sqlite3_file*, int*); IOMETHODS( proxyIoFinder, /* Finder function name */ proxyIoMethods, /* sqlite3_io_methods object name */ proxyClose, /* xClose method */ proxyLock, /* xLock method */ proxyUnlock, /* xUnlock method */ proxyCheckReservedLock /* xCheckReservedLock method */ |
︙ | ︙ | |||
4135 4136 4137 4138 4139 4140 4141 | const sqlite3_io_methods *pLockingStyle; unixFile *pNew = (unixFile *)pId; int rc = SQLITE_OK; assert( pNew->pLock==NULL ); assert( pNew->pOpen==NULL ); | | | | < < < < < < | 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 | const sqlite3_io_methods *pLockingStyle; unixFile *pNew = (unixFile *)pId; int rc = SQLITE_OK; assert( pNew->pLock==NULL ); assert( pNew->pOpen==NULL ); /* Parameter isDelete is only used on vxworks. ** Express this explicitly here to prevent compiler warnings ** about unused parameters. */ #if !OS_VXWORKS UNUSED_PARAMETER(isDelete); #endif OSTRACE3("OPEN %-3d %s\n", h, zFilename); pNew->h = h; pNew->dirfd = dirfd; SET_THREADID(pNew); #if OS_VXWORKS |
︙ | ︙ | |||
4520 4521 4522 4523 4524 4525 4526 | return SQLITE_IOERR_ACCESS; } useProxy = !(fsInfo.f_flags&MNT_LOCAL); } if( useProxy ){ rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, isDelete); if( rc==SQLITE_OK ){ | | | 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 | return SQLITE_IOERR_ACCESS; } useProxy = !(fsInfo.f_flags&MNT_LOCAL); } if( useProxy ){ rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, isDelete); if( rc==SQLITE_OK ){ rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:"); } return rc; } } #endif return fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, isDelete); |
︙ | ︙ | |||
4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 | UNUSED_PARAMETER(NotUsed3); return 0; } /* ************************ End of sqlite3_vfs methods *************************** ******************************************************************************/ /* ** Initialize the operating system interface. ** ** This routine registers all VFS implementations for unix-like operating ** systems. This routine, and the sqlite3_os_end() routine that follows, ** should be the only routines in this file that are visible from other | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 | UNUSED_PARAMETER(NotUsed3); return 0; } /* ************************ End of sqlite3_vfs methods *************************** ******************************************************************************/ /****************************************************************************** ************************** Begin Proxy Locking ******************************** ** ** Proxy locking is a "uber-locking-method" in this sense: It uses the ** other locking methods on secondary lock files. Proxy locking is a ** meta-layer over top of the primitive locking implemented above. For ** this reason, the division that implements of proxy locking is deferred ** until late in the file (here) after all of the other I/O methods have ** been defined - so that the primitive locking methods are available ** as services to help with the implementation of proxy locking. ** **** ** ** The default locking schemes in SQLite use byte-range locks on the ** database file to coordinate safe, concurrent access by multiple readers ** and writers [http://sqlite.org/lockingv3.html]. The five file locking ** states (UNLOCKED, PENDING, SHARED, RESERVED, EXCLUSIVE) are implemented ** as POSIX read & write locks over fixed set of locations (via fsctl), ** on AFP and SMB only exclusive byte-range locks are available via fsctl ** with _IOWR('z', 23, struct ByteRangeLockPB2) to track the same 5 states. ** To simulate a F_RDLCK on the shared range, on AFP a randomly selected ** address in the shared range is taken for a SHARED lock, the entire ** shared range is taken for an EXCLUSIVE lock): ** ** PENDING_BYTE 0x40000000 ** RESERVED_BYTE 0x40000001 ** SHARED_RANGE 0x40000002 -> 0x40000200 ** ** This works well on the local file system, but shows a nearly 100x ** slowdown in read performance on AFP because the AFP client disables ** the read cache when byte-range locks are present. Enabling the read ** cache exposes a cache coherency problem that is present on all OS X ** supported network file systems. NFS and AFP both observe the ** close-to-open semantics for ensuring cache coherency ** [http://nfs.sourceforge.net/#faq_a8], which does not effectively ** address the requirements for concurrent database access by multiple ** readers and writers ** [http://www.nabble.com/SQLite-on-NFS-cache-coherency-td15655701.html]. ** ** To address the performance and cache coherency issues, proxy file locking ** changes the way database access is controlled by limiting access to a ** single host at a time and moving file locks off of the database file ** and onto a proxy file on the local file system. ** ** ** Using proxy locks ** ----------------- ** ** C APIs ** ** sqlite3_file_control(db, dbname, SQLITE_SET_LOCKPROXYFILE, ** <proxy_path> | ":auto:"); ** sqlite3_file_control(db, dbname, SQLITE_GET_LOCKPROXYFILE, &<proxy_path>); ** ** ** SQL pragmas ** ** PRAGMA [database.]lock_proxy_file=<proxy_path> | :auto: ** PRAGMA [database.]lock_proxy_file ** ** Specifying ":auto:" means that if there is a conch file with a matching ** host ID in it, the proxy path in the conch file will be used, otherwise ** a proxy path based on the user's temp dir ** (via confstr(_CS_DARWIN_USER_TEMP_DIR,...)) will be used and the ** actual proxy file name is generated from the name and path of the ** database file. For example: ** ** For database path "/Users/me/foo.db" ** The lock path will be "<tmpdir>/sqliteplocks/_Users_me_foo.db:auto:") ** ** Once a lock proxy is configured for a database connection, it can not ** be removed, however it may be switched to a different proxy path via ** the above APIs (assuming the conch file is not being held by another ** connection or process). ** ** ** How proxy locking works ** ----------------------- ** ** Proxy file locking relies primarily on two new supporting files: ** ** * conch file to limit access to the database file to a single host ** at a time ** ** * proxy file to act as a proxy for the advisory locks normally ** taken on the database ** ** The conch file - to use a proxy file, sqlite must first "hold the conch" ** by taking an sqlite-style shared lock on the conch file, reading the ** contents and comparing the host's unique host ID (see below) and lock ** proxy path against the values stored in the conch. The conch file is ** stored in the same directory as the database file and the file name ** is patterned after the database file name as ".<databasename>-conch". ** If the conch file does not exist, or it's contents do not match the ** host ID and/or proxy path, then the lock is escalated to an exclusive ** lock and the conch file contents is updated with the host ID and proxy ** path and the lock is downgraded to a shared lock again. If the conch ** is held by another process (with a shared lock), the exclusive lock ** will fail and SQLITE_BUSY is returned. ** ** The proxy file - a single-byte file used for all advisory file locks ** normally taken on the database file. This allows for safe sharing ** of the database file for multiple readers and writers on the same ** host (the conch ensures that they all use the same local lock file). ** ** There is a third file - the host ID file - used as a persistent record ** of a unique identifier for the host, a 128-byte unique host id file ** in the path defined by the HOSTIDPATH macro (default value is ** /Library/Caches/.com.apple.sqliteConchHostId). ** ** Requesting the lock proxy does not immediately take the conch, it is ** only taken when the first request to lock database file is made. ** This matches the semantics of the traditional locking behavior, where ** opening a connection to a database file does not take a lock on it. ** The shared lock and an open file descriptor are maintained until ** the connection to the database is closed. ** ** The proxy file and the lock file are never deleted so they only need ** to be created the first time they are used. ** ** Configuration options ** --------------------- ** ** SQLITE_PREFER_PROXY_LOCKING ** ** Database files accessed on non-local file systems are ** automatically configured for proxy locking, lock files are ** named automatically using the same logic as ** PRAGMA lock_proxy_file=":auto:" ** ** SQLITE_PROXY_DEBUG ** ** Enables the logging of error messages during host id file ** retrieval and creation ** ** HOSTIDPATH ** ** Overrides the default host ID file path location ** ** LOCKPROXYDIR ** ** Overrides the default directory used for lock proxy files that ** are named automatically via the ":auto:" setting ** ** SQLITE_DEFAULT_PROXYDIR_PERMISSIONS ** ** Permissions to use when creating a directory for storing the ** lock proxy files, only used when LOCKPROXYDIR is not set. ** ** ** As mentioned above, when compiled with SQLITE_PREFER_PROXY_LOCKING, ** setting the environment variable SQLITE_FORCE_PROXY_LOCKING to 1 will ** force proxy locking to be used for every database file opened, and 0 ** will force automatic proxy locking to be disabled for all database ** files (explicity calling the SQLITE_SET_LOCKPROXYFILE pragma or ** sqlite_file_control API is not affected by SQLITE_FORCE_PROXY_LOCKING). */ /* ** Proxy locking is only available on MacOSX */ #if defined(__DARWIN__) && SQLITE_ENABLE_LOCKING_STYLE #ifdef SQLITE_TEST /* simulate multiple hosts by creating unique hostid file paths */ int sqlite3_hostid_num = 0; #endif /* ** The proxyLockingContext has the path and file structures for the remote ** and local proxy files in it */ typedef struct proxyLockingContext proxyLockingContext; struct proxyLockingContext { unixFile *conchFile; /* Open conch file */ char *conchFilePath; /* Name of the conch file */ unixFile *lockProxy; /* Open proxy lock file */ char *lockProxyPath; /* Name of the proxy lock file */ char *dbPath; /* Name of the open file */ int conchHeld; /* True if the conch is currently held */ void *oldLockingContext; /* Original lockingcontext to restore on close */ sqlite3_io_methods const *pOldMethod; /* Original I/O methods for close */ }; /* HOSTIDLEN and CONCHLEN both include space for the string ** terminating nul */ #define HOSTIDLEN 128 #define CONCHLEN (MAXPATHLEN+HOSTIDLEN+1) #ifndef HOSTIDPATH # define HOSTIDPATH "/Library/Caches/.com.apple.sqliteConchHostId" #endif /* basically a copy of unixRandomness with different ** test behavior built in */ static int proxyGenerateHostID(char *pHostID){ int pid, fd, len; unsigned char *key = (unsigned char *)pHostID; memset(key, 0, HOSTIDLEN); len = 0; fd = open("/dev/urandom", O_RDONLY); if( fd>=0 ){ len = read(fd, key, HOSTIDLEN); close(fd); /* silently leak the fd if it fails */ } if( len < HOSTIDLEN ){ time_t t; time(&t); memcpy(key, &t, sizeof(t)); pid = getpid(); memcpy(&key[sizeof(t)], &pid, sizeof(pid)); } #ifdef MAKE_PRETTY_HOSTID { int i; /* filter the bytes into printable ascii characters and NUL terminate */ key[(HOSTIDLEN-1)] = 0x00; for( i=0; i<(HOSTIDLEN-1); i++ ){ unsigned char pa = key[i]&0x7F; if( pa<0x20 ){ key[i] = (key[i]&0x80 == 0x80) ? pa+0x40 : pa+0x20; }else if( pa==0x7F ){ key[i] = (key[i]&0x80 == 0x80) ? pa=0x20 : pa+0x7E; } } } #endif return SQLITE_OK; } /* writes the host id path to path, path should be an pre-allocated buffer ** with enough space for a path */ static void proxyGetHostIDPath(char *path, size_t len){ strlcpy(path, HOSTIDPATH, len); #ifdef SQLITE_TEST if( sqlite3_hostid_num>0 ){ char suffix[2] = "1"; suffix[0] = suffix[0] + sqlite3_hostid_num; strlcat(path, suffix, len); } #endif OSTRACE3("GETHOSTIDPATH %s pid=%d\n", path, getpid()); } /* get the host ID from a sqlite hostid file stored in the ** user-specific tmp directory, create the ID if it's not there already */ static int proxyGetHostID(char *pHostID, int *pError){ int fd; char path[MAXPATHLEN]; size_t len; int rc=SQLITE_OK; proxyGetHostIDPath(path, MAXPATHLEN); /* try to create the host ID file, if it already exists read the contents */ fd = open(path, O_CREAT|O_WRONLY|O_EXCL, 0644); if( fd<0 ){ int err=errno; if( err!=EEXIST ){ #ifdef SQLITE_PROXY_DEBUG /* set the sqlite error message instead */ fprintf(stderr, "sqlite error creating host ID file %s: %s\n", path, strerror(err)); #endif return SQLITE_PERM; } /* couldn't create the file, read it instead */ fd = open(path, O_RDONLY|O_EXCL); if( fd<0 ){ #ifdef SQLITE_PROXY_DEBUG /* set the sqlite error message instead */ int err = errno; fprintf(stderr, "sqlite error opening host ID file %s: %s\n", path, strerror(err)); #endif return SQLITE_PERM; } len = pread(fd, pHostID, HOSTIDLEN, 0); if( len<0 ){ *pError = errno; rc = SQLITE_IOERR_READ; }else if( len<HOSTIDLEN ){ *pError = 0; rc = SQLITE_IOERR_SHORT_READ; } close(fd); /* silently leak the fd if it fails */ OSTRACE3("GETHOSTID read %s pid=%d\n", pHostID, getpid()); return rc; }else{ /* we're creating the host ID file (use a random string of bytes) */ proxyGenerateHostID(pHostID); len = pwrite(fd, pHostID, HOSTIDLEN, 0); if( len<0 ){ *pError = errno; rc = SQLITE_IOERR_WRITE; }else if( len<HOSTIDLEN ){ *pError = 0; rc = SQLITE_IOERR_WRITE; } close(fd); /* silently leak the fd if it fails */ OSTRACE3("GETHOSTID wrote %s pid=%d\n", pHostID, getpid()); return rc; } } static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){ int len; int dbLen; int i; #ifdef LOCKPROXYDIR len = strlcpy(lPath, LOCKPROXYDIR, maxLen); #else # ifdef _CS_DARWIN_USER_TEMP_DIR { confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen); len = strlcat(lPath, "sqliteplocks", maxLen); if( mkdir(lPath, SQLITE_DEFAULT_PROXYDIR_PERMISSIONS) ){ /* if mkdir fails, handle as lock file creation failure */ int err = errno; # ifdef SQLITE_DEBUG if( err!=EEXIST ){ fprintf(stderr, "proxyGetLockPath: mkdir(%s,0%o) error %d %s\n", lPath, SQLITE_DEFAULT_PROXYDIR_PERMISSIONS, err, strerror(err)); } # endif }else{ OSTRACE3("GETLOCKPATH mkdir %s pid=%d\n", lPath, getpid()); } } # else len = strlcpy(lPath, "/tmp/", maxLen); # endif #endif if( lPath[len-1]!='/' ){ len = strlcat(lPath, "/", maxLen); } /* transform the db path to a unique cache name */ dbLen = strlen(dbPath); for( i=0; i<dbLen && (i+len+7)<maxLen; i++){ char c = dbPath[i]; lPath[i+len] = (c=='/')?'_':c; } lPath[i+len]='\0'; strlcat(lPath, ":auto:", maxLen); return SQLITE_OK; } /* ** Create a new VFS file descriptor (stored in memory obtained from ** sqlite3_malloc) and open the file named "path" in the file descriptor. ** ** The caller is responsible not only for closing the file descriptor ** but also for freeing the memory associated with the file descriptor. */ static int proxyCreateUnixFile(const char *path, unixFile **ppFile) { int fd; int dirfd = -1; unixFile *pNew; int rc = SQLITE_OK; sqlite3_vfs dummyVfs; fd = open(path, O_RDWR | O_CREAT, SQLITE_DEFAULT_FILE_PERMISSIONS); if( fd<0 ){ return SQLITE_CANTOPEN; } pNew = (unixFile *)sqlite3_malloc(sizeof(unixFile)); if( pNew==NULL ){ rc = SQLITE_NOMEM; goto end_create_proxy; } memset(pNew, 0, sizeof(unixFile)); dummyVfs.pAppData = (void*)autolockIoFinder; rc = fillInUnixFile(&dummyVfs, fd, dirfd, (sqlite3_file*)pNew, path, 0, 0); if( rc==SQLITE_OK ){ *ppFile = pNew; return SQLITE_OK; } end_create_proxy: close(fd); /* silently leak fd if error, we're already in error */ sqlite3_free(pNew); return rc; } /* takes the conch by taking a shared lock and read the contents conch, if ** lockPath is non-NULL, the host ID and lock file path must match. A NULL ** lockPath means that the lockPath in the conch file will be used if the ** host IDs match, or a new lock path will be generated automatically ** and written to the conch file. */ static int proxyTakeConch(unixFile *pFile){ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; if( pCtx->conchHeld>0 ){ return SQLITE_OK; }else{ unixFile *conchFile = pCtx->conchFile; char testValue[CONCHLEN]; char conchValue[CONCHLEN]; char lockPath[MAXPATHLEN]; char *tLockPath = NULL; int rc = SQLITE_OK; int readRc = SQLITE_OK; int syncPerms = 0; OSTRACE4("TAKECONCH %d for %s pid=%d\n", conchFile->h, (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), getpid()); rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, SHARED_LOCK); if( rc==SQLITE_OK ){ int pError = 0; memset(testValue, 0, CONCHLEN); // conch is fixed size rc = proxyGetHostID(testValue, &pError); if( (rc&0xff)==SQLITE_IOERR ){ pFile->lastErrno = pError; } if( pCtx->lockProxyPath ){ strlcpy(&testValue[HOSTIDLEN], pCtx->lockProxyPath, MAXPATHLEN); } } if( rc!=SQLITE_OK ){ goto end_takeconch; } readRc = unixRead((sqlite3_file *)conchFile, conchValue, CONCHLEN, 0); if( readRc!=SQLITE_IOERR_SHORT_READ ){ if( readRc!=SQLITE_OK ){ if( (rc&0xff)==SQLITE_IOERR ){ pFile->lastErrno = conchFile->lastErrno; } rc = readRc; goto end_takeconch; } /* if the conch has data compare the contents */ if( !pCtx->lockProxyPath ){ /* for auto-named local lock file, just check the host ID and we'll ** use the local lock file path that's already in there */ if( !memcmp(testValue, conchValue, HOSTIDLEN) ){ tLockPath = (char *)&conchValue[HOSTIDLEN]; goto end_takeconch; } }else{ /* we've got the conch if conchValue matches our path and host ID */ if( !memcmp(testValue, conchValue, CONCHLEN) ){ goto end_takeconch; } } }else{ /* a short read means we're "creating" the conch (even though it could ** have been user-intervention), if we acquire the exclusive lock, ** we'll try to match the current on-disk permissions of the database */ syncPerms = 1; } /* either conch was emtpy or didn't match */ if( !pCtx->lockProxyPath ){ proxyGetLockPath(pCtx->dbPath, lockPath, MAXPATHLEN); tLockPath = lockPath; strlcpy(&testValue[HOSTIDLEN], lockPath, MAXPATHLEN); } /* update conch with host and path (this will fail if other process ** has a shared lock already) */ rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, EXCLUSIVE_LOCK); if( rc==SQLITE_OK ){ rc = unixWrite((sqlite3_file *)conchFile, testValue, CONCHLEN, 0); if( rc==SQLITE_OK && syncPerms ){ struct stat buf; int err = fstat(pFile->h, &buf); if( err==0 ){ /* try to match the database file permissions, ignore failure */ #ifndef SQLITE_PROXY_DEBUG fchmod(conchFile->h, buf.st_mode); #else if( fchmod(conchFile->h, buf.st_mode)!=0 ){ int code = errno; fprintf(stderr, "fchmod %o FAILED with %d %s\n", buf.st_mode, code, strerror(code)); } else { fprintf(stderr, "fchmod %o SUCCEDED\n",buf.st_mode); } }else{ int code = errno; fprintf(stderr, "STAT FAILED[%d] with %d %s\n", err, code, strerror(code)); #endif } } } conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, SHARED_LOCK); end_takeconch: OSTRACE2("TRANSPROXY: CLOSE %d\n", pFile->h); if( rc==SQLITE_OK && pFile->openFlags ){ if( pFile->h>=0 ){ #ifdef STRICT_CLOSE_ERROR if( close(pFile->h) ){ pFile->lastErrno = errno; return SQLITE_IOERR_CLOSE; } #else close(pFile->h); /* silently leak fd if fail */ #endif } pFile->h = -1; int fd = open(pCtx->dbPath, pFile->openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS); OSTRACE2("TRANSPROXY: OPEN %d\n", fd); if( fd>=0 ){ pFile->h = fd; }else{ rc=SQLITE_CANTOPEN; // SQLITE_BUSY? proxyTakeConch called during locking } } if( rc==SQLITE_OK && !pCtx->lockProxy ){ char *path = tLockPath ? tLockPath : pCtx->lockProxyPath; // ACS: Need to make a copy of path sometimes rc = proxyCreateUnixFile(path, &pCtx->lockProxy); } if( rc==SQLITE_OK ){ pCtx->conchHeld = 1; if( tLockPath ){ pCtx->lockProxyPath = sqlite3DbStrDup(0, tLockPath); if( pCtx->lockProxy->pMethod == &afpIoMethods ){ ((afpLockingContext *)pCtx->lockProxy->lockingContext)->dbPath = pCtx->lockProxyPath; } } } else { conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK); } OSTRACE3("TAKECONCH %d %s\n", conchFile->h, rc==SQLITE_OK?"ok":"failed"); return rc; } } /* ** If pFile holds a lock on a conch file, then release that lock. */ static int proxyReleaseConch(unixFile *pFile){ int rc; /* Subroutine return code */ proxyLockingContext *pCtx; /* The locking context for the proxy lock */ unixFile *conchFile; /* Name of the conch file */ pCtx = (proxyLockingContext *)pFile->lockingContext; conchFile = pCtx->conchFile; OSTRACE4("RELEASECONCH %d for %s pid=%d\n", conchFile->h, (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), getpid()); pCtx->conchHeld = 0; rc = conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK); OSTRACE3("RELEASECONCH %d %s\n", conchFile->h, (rc==SQLITE_OK ? "ok" : "failed")); return rc; } /* ** Given the name of a database file, compute the name of its conch file. ** Store the conch filename in memory obtained from sqlite3_malloc(). ** Make *pConchPath point to the new name. Return SQLITE_OK on success ** or SQLITE_NOMEM if unable to obtain memory. ** ** The caller is responsible for ensuring that the allocated memory ** space is eventually freed. ** ** *pConchPath is set to NULL if a memory allocation error occurs. */ static int proxyCreateConchPathname(char *dbPath, char **pConchPath){ int i; /* Loop counter */ int len = strlen(dbPath); /* Length of database filename - dbPath */ char *conchPath; /* buffer in which to construct conch name */ /* Allocate space for the conch filename and initialize the name to ** the name of the original database file. */ *pConchPath = conchPath = (char *)sqlite3_malloc(len + 8); if( conchPath==0 ){ return SQLITE_NOMEM; } memcpy(conchPath, dbPath, len+1); /* now insert a "." before the last / character */ for( i=(len-1); i>=0; i-- ){ if( conchPath[i]=='/' ){ i++; break; } } conchPath[i]='.'; while ( i<len ){ conchPath[i+1]=dbPath[i]; i++; } /* append the "-conch" suffix to the file */ memcpy(&conchPath[i+1], "-conch", 7); assert( strlen(conchPath) == len+7 ); return SQLITE_OK; } /* Takes a fully configured proxy locking-style unix file and switches ** the local lock file path */ static int switchLockProxyPath(unixFile *pFile, const char *path) { proxyLockingContext *pCtx = (proxyLockingContext*)pFile->lockingContext; char *oldPath = pCtx->lockProxyPath; int rc = SQLITE_OK; if( pFile->locktype!=NO_LOCK ){ return SQLITE_BUSY; } /* nothing to do if the path is NULL, :auto: or matches the existing path */ if( !path || path[0]=='\0' || !strcmp(path, ":auto:") || (oldPath && !strncmp(oldPath, path, MAXPATHLEN)) ){ return SQLITE_OK; }else{ unixFile *lockProxy = pCtx->lockProxy; pCtx->lockProxy=NULL; pCtx->conchHeld = 0; if( lockProxy!=NULL ){ rc=lockProxy->pMethod->xClose((sqlite3_file *)lockProxy); if( rc ) return rc; sqlite3_free(lockProxy); } sqlite3_free(oldPath); pCtx->lockProxyPath = sqlite3DbStrDup(0, path); } return rc; } /* ** pFile is a file that has been opened by a prior xOpen call. dbPath ** is a string buffer at least MAXPATHLEN+1 characters in size. ** ** This routine find the filename associated with pFile and writes it ** int dbPath. */ static int proxyGetDbPathForUnixFile(unixFile *pFile, char *dbPath){ #if defined(__DARWIN__) if( pFile->pMethod == &afpIoMethods ){ /* afp style keeps a reference to the db path in the filePath field ** of the struct */ assert( strlen((char*)pFile->lockingContext)<=MAXPATHLEN ); strcpy(dbPath, ((afpLockingContext *)pFile->lockingContext)->dbPath); }else #endif if( pFile->pMethod == &dotlockIoMethods ){ /* dot lock style uses the locking context to store the dot lock ** file path */ int len = strlen((char *)pFile->lockingContext) - strlen(DOTLOCK_SUFFIX); memcpy(dbPath, (char *)pFile->lockingContext, len + 1); }else{ /* all other styles use the locking context to store the db file path */ assert( strlen((char*)pFile->lockingContext)<=MAXPATHLEN ); strcpy(dbPath, (char *)pFile->lockingContext); } return SQLITE_OK; } /* ** Takes an already filled in unix file and alters it so all file locking ** will be performed on the local proxy lock file. The following fields ** are preserved in the locking context so that they can be restored and ** the unix structure properly cleaned up at close time: ** ->lockingContext ** ->pMethod */ static int proxyTransformUnixFile(unixFile *pFile, const char *path) { proxyLockingContext *pCtx; char dbPath[MAXPATHLEN+1]; /* Name of the database file */ char *lockPath=NULL; int rc = SQLITE_OK; if( pFile->locktype!=NO_LOCK ){ return SQLITE_BUSY; } proxyGetDbPathForUnixFile(pFile, dbPath); if( !path || path[0]=='\0' || !strcmp(path, ":auto:") ){ lockPath=NULL; }else{ lockPath=(char *)path; } OSTRACE4("TRANSPROXY %d for %s pid=%d\n", pFile->h, (lockPath ? lockPath : ":auto:"), getpid()); pCtx = sqlite3_malloc( sizeof(*pCtx) ); if( pCtx==0 ){ return SQLITE_NOMEM; } memset(pCtx, 0, sizeof(*pCtx)); rc = proxyCreateConchPathname(dbPath, &pCtx->conchFilePath); if( rc==SQLITE_OK ){ rc = proxyCreateUnixFile(pCtx->conchFilePath, &pCtx->conchFile); } if( rc==SQLITE_OK && lockPath ){ pCtx->lockProxyPath = sqlite3DbStrDup(0, lockPath); } if( rc==SQLITE_OK ){ /* all memory is allocated, proxys are created and assigned, ** switch the locking context and pMethod then return. */ pCtx->dbPath = sqlite3DbStrDup(0, dbPath); pCtx->oldLockingContext = pFile->lockingContext; pFile->lockingContext = pCtx; pCtx->pOldMethod = pFile->pMethod; pFile->pMethod = &proxyIoMethods; }else{ if( pCtx->conchFile ){ rc = pCtx->conchFile->pMethod->xClose((sqlite3_file *)pCtx->conchFile); if( rc ) return rc; sqlite3_free(pCtx->conchFile); } sqlite3_free(pCtx->conchFilePath); sqlite3_free(pCtx); } OSTRACE3("TRANSPROXY %d %s\n", pFile->h, (rc==SQLITE_OK ? "ok" : "failed")); return rc; } /* ** This routine handles sqlite3_file_control() calls that are specific ** to proxy locking. */ static int proxyFileControl(sqlite3_file *id, int op, void *pArg){ switch( op ){ case SQLITE_GET_LOCKPROXYFILE: { unixFile *pFile = (unixFile*)id; if( pFile->pMethod == &proxyIoMethods ){ proxyLockingContext *pCtx = (proxyLockingContext*)pFile->lockingContext; proxyTakeConch(pFile); if( pCtx->lockProxyPath ){ *(const char **)pArg = pCtx->lockProxyPath; }else{ *(const char **)pArg = ":auto: (not held)"; } } else { *(const char **)pArg = NULL; } return SQLITE_OK; } case SQLITE_SET_LOCKPROXYFILE: { unixFile *pFile = (unixFile*)id; int rc = SQLITE_OK; int isProxyStyle = (pFile->pMethod == &proxyIoMethods); if( pArg==NULL || (const char *)pArg==0 ){ if( isProxyStyle ){ /* turn off proxy locking - not supported */ rc = SQLITE_ERROR /*SQLITE_PROTOCOL? SQLITE_MISUSE?*/; }else{ /* turn off proxy locking - already off - NOOP */ rc = SQLITE_OK; } }else{ const char *proxyPath = (const char *)pArg; if( isProxyStyle ){ proxyLockingContext *pCtx = (proxyLockingContext*)pFile->lockingContext; if( !strcmp(pArg, ":auto:") || (pCtx->lockProxyPath && !strncmp(pCtx->lockProxyPath, proxyPath, MAXPATHLEN)) ){ rc = SQLITE_OK; }else{ rc = switchLockProxyPath(pFile, proxyPath); } }else{ /* turn on proxy file locking */ rc = proxyTransformUnixFile(pFile, proxyPath); } } return rc; } default: { assert( 0 ); /* The call assures that only valid opcodes are sent */ } } /*NOTREACHED*/ return SQLITE_ERROR; } /* ** Within this division (the proxying locking implementation) the procedures ** above this point are all utilities. The lock-related methods of the ** proxy-locking sqlite3_io_method object follow. */ /* ** This routine checks if there is a RESERVED lock held on the specified ** file by this or any other process. If such a lock is held, set *pResOut ** to a non-zero value otherwise *pResOut is set to zero. The return value ** is set to SQLITE_OK unless an I/O error occurs during lock checking. */ static int proxyCheckReservedLock(sqlite3_file *id, int *pResOut) { unixFile *pFile = (unixFile*)id; int rc = proxyTakeConch(pFile); if( rc==SQLITE_OK ){ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; unixFile *proxy = pCtx->lockProxy; return proxy->pMethod->xCheckReservedLock((sqlite3_file*)proxy, pResOut); } return rc; } /* ** Lock the file with the lock specified by parameter locktype - one ** of the following: ** ** (1) SHARED_LOCK ** (2) RESERVED_LOCK ** (3) PENDING_LOCK ** (4) EXCLUSIVE_LOCK ** ** Sometimes when requesting one lock state, additional lock states ** are inserted in between. The locking might fail on one of the later ** transitions leaving the lock state different from what it started but ** still short of its goal. The following chart shows the allowed ** transitions and the inserted intermediate states: ** ** UNLOCKED -> SHARED ** SHARED -> RESERVED ** SHARED -> (PENDING) -> EXCLUSIVE ** RESERVED -> (PENDING) -> EXCLUSIVE ** PENDING -> EXCLUSIVE ** ** This routine will only increase a lock. Use the sqlite3OsUnlock() ** routine to lower a locking level. */ static int proxyLock(sqlite3_file *id, int locktype) { unixFile *pFile = (unixFile*)id; int rc = proxyTakeConch(pFile); if( rc==SQLITE_OK ){ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; unixFile *proxy = pCtx->lockProxy; rc = proxy->pMethod->xLock((sqlite3_file*)proxy, locktype); pFile->locktype = proxy->locktype; } return rc; } /* ** Lower the locking level on file descriptor pFile to locktype. locktype ** must be either NO_LOCK or SHARED_LOCK. ** ** If the locking level of the file descriptor is already at or below ** the requested locking level, this routine is a no-op. */ static int proxyUnlock(sqlite3_file *id, int locktype) { unixFile *pFile = (unixFile*)id; int rc = proxyTakeConch(pFile); if( rc==SQLITE_OK ){ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; unixFile *proxy = pCtx->lockProxy; rc = proxy->pMethod->xUnlock((sqlite3_file*)proxy, locktype); pFile->locktype = proxy->locktype; } return rc; } /* ** Close a file that uses proxy locks. */ static int proxyClose(sqlite3_file *id) { if( id ){ unixFile *pFile = (unixFile*)id; proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; unixFile *lockProxy = pCtx->lockProxy; unixFile *conchFile = pCtx->conchFile; int rc = SQLITE_OK; if( lockProxy ){ rc = lockProxy->pMethod->xUnlock((sqlite3_file*)lockProxy, NO_LOCK); if( rc ) return rc; rc = lockProxy->pMethod->xClose((sqlite3_file*)lockProxy); if( rc ) return rc; sqlite3_free(lockProxy); pCtx->lockProxy = 0; } if( conchFile ){ if( pCtx->conchHeld ){ rc = proxyReleaseConch(pFile); if( rc ) return rc; } rc = conchFile->pMethod->xClose((sqlite3_file*)conchFile); if( rc ) return rc; sqlite3_free(conchFile); } sqlite3_free(pCtx->lockProxyPath); sqlite3_free(pCtx->conchFilePath); sqlite3_free(pCtx->dbPath); /* restore the original locking context and pMethod then close it */ pFile->lockingContext = pCtx->oldLockingContext; pFile->pMethod = pCtx->pOldMethod; sqlite3_free(pCtx); return pFile->pMethod->xClose(id); } return SQLITE_OK; } #endif /* defined(__DARWIN__) && SQLITE_ENABLE_LOCKING_STYLE */ /* ** The proxy locking style is intended for use with AFP filesystems. ** And since AFP is only supported on MacOSX, the proxy locking is also ** restricted to MacOSX. ** ** ******************* End of the proxy lock implementation ********************** ******************************************************************************/ /* ** Initialize the operating system interface. ** ** This routine registers all VFS implementations for unix-like operating ** systems. This routine, and the sqlite3_os_end() routine that follows, ** should be the only routines in this file that are visible from other |
︙ | ︙ |
Changes to src/test1.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing all sorts of SQLite interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing all sorts of SQLite interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** ** $Id: test1.c,v 1.335 2008/12/03 22:32:45 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> /* |
︙ | ︙ | |||
4912 4913 4914 4915 4916 4917 4918 | extern int sqlite3_sync_count, sqlite3_fullsync_count; extern int sqlite3_opentemp_count; extern int sqlite3_like_count; extern int sqlite3_xferopt_count; extern int sqlite3_pager_readdb_count; extern int sqlite3_pager_writedb_count; extern int sqlite3_pager_writej_count; | | | 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 | extern int sqlite3_sync_count, sqlite3_fullsync_count; extern int sqlite3_opentemp_count; extern int sqlite3_like_count; extern int sqlite3_xferopt_count; extern int sqlite3_pager_readdb_count; extern int sqlite3_pager_writedb_count; extern int sqlite3_pager_writej_count; #if defined(__linux__) && defined(SQLITE_TEST) && SQLITE_THREADSAFE extern int threadsOverrideEachOthersLocks; #endif #if SQLITE_OS_WIN extern int sqlite3_os_type; #endif #ifdef SQLITE_DEBUG extern int sqlite3WhereTrace; |
︙ | ︙ | |||
4966 4967 4968 4969 4970 4971 4972 | (char*)&sqlite3_pager_writedb_count, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite3_pager_writej_count", (char*)&sqlite3_pager_writej_count, TCL_LINK_INT); #ifndef SQLITE_OMIT_UTF16 Tcl_LinkVar(interp, "unaligned_string_counter", (char*)&unaligned_string_counter, TCL_LINK_INT); #endif | | | 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 | (char*)&sqlite3_pager_writedb_count, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite3_pager_writej_count", (char*)&sqlite3_pager_writej_count, TCL_LINK_INT); #ifndef SQLITE_OMIT_UTF16 Tcl_LinkVar(interp, "unaligned_string_counter", (char*)&unaligned_string_counter, TCL_LINK_INT); #endif #if defined(__linux__) && defined(SQLITE_TEST) && SQLITE_THREADSAFE Tcl_LinkVar(interp, "threadsOverrideEachOthersLocks", (char*)&threadsOverrideEachOthersLocks, TCL_LINK_INT); #endif #ifndef SQLITE_OMIT_UTF16 Tcl_LinkVar(interp, "sqlite_last_needed_collation", (char*)&pzNeededCollation, TCL_LINK_STRING|TCL_LINK_READ_ONLY); #endif |
︙ | ︙ |
Changes to test/tkt3472.test.
1 2 3 4 5 6 7 8 9 10 11 | # 2008 November 11 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # | | | < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # 2008 November 11 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # $Id: tkt3472.test,v 1.4 2008/12/03 22:32:45 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl if {![info exists threadsOverrideEachOthersLocks]} { finish_test return } set ::correctvalue $threadsOverrideEachOthersLocks puts "threadsOverrideEachOthersLocks = $::correctvalue" |
︙ | ︙ |