README
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:6k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. # $Id: README,v 11.2 1999/11/21 18:12:48 bostic Exp $
  2. Note: this only applies to locking using test-and-set and fcntl calls,
  3. pthreads were added after this was written.
  4. Resource locking routines: lock based on a db_mutex_t.  All this gunk
  5. (including trying to make assembly code portable), is necessary because
  6. System V semaphores require system calls for uncontested locks and we
  7. don't want to make two system calls per resource lock.
  8. First, this is how it works.  The db_mutex_t structure contains a resource
  9. test-and-set lock (tsl), a file offset, a pid for debugging and statistics
  10. information.
  11. If HAVE_MUTEX_THREADS is defined (i.e. we know how to do test-and-sets
  12. for this compiler/architecture combination), we try and lock the resource
  13. tsl __os_spin() times.  If we can't acquire the lock that way, we use a
  14. system call to sleep for 1ms, 2ms, 4ms, etc.  (The time is bounded at 1
  15. second, just in case.)  Using the timer backoff means that there are two
  16. assumptions: that locks are held for brief periods (never over system
  17. calls or I/O) and that locks are not hotly contested.
  18. If HAVE_MUTEX_THREADS is not defined, i.e. we can't do test-and-sets, we
  19. use a file descriptor to do byte locking on a file at a specified offset.
  20. In this case, ALL of the locking is done in the kernel.  Because file
  21. descriptors are allocated per process, we have to provide the file
  22. descriptor as part of the lock call.  We still have to do timer backoff
  23. because we need to be able to block ourselves, i.e. the lock manager
  24. causes processes to wait by having the process acquire a mutex and then
  25. attempting to re-acquire the mutex.  There's no way to use kernel locking
  26. to block yourself, i.e. if you hold a lock and attempt to re-acquire it,
  27. the attempt will succeed.
  28. Next, let's talk about why it doesn't work the way a reasonable person
  29. would think it should work.
  30. Ideally, we'd have the ability to try to lock the resource tsl, and if
  31. that fails, increment a counter of waiting processes, then block in the
  32. kernel until the tsl is released.  The process holding the resource tsl
  33. would see the wait counter when it went to release the resource tsl, and
  34. would wake any waiting processes up after releasing the lock.  This would
  35. actually require both another tsl (call it the mutex tsl) and
  36. synchronization between the call that blocks in the kernel and the actual
  37. resource tsl.  The mutex tsl would be used to protect accesses to the
  38. db_mutex_t itself.  Locking the mutex tsl would be done by a busy loop,
  39. which is safe because processes would never block holding that tsl (all
  40. they would do is try to obtain the resource tsl and set/check the wait
  41. count).  The problem in this model is that the blocking call into the
  42. kernel requires a blocking semaphore, i.e. one whose normal state is
  43. locked.
  44. The only portable forms of locking under UNIX are fcntl(2) on a file
  45. descriptor/offset, and System V semaphores.  Neither of these locking
  46. methods are sufficient to solve the problem.
  47. The problem with fcntl locking is that only the process that obtained the
  48. lock can release it.  Remember, we want the normal state of the kernel
  49. semaphore to be locked.  So, if the creator of the db_mutex_t were to
  50. initialize the lock to "locked", then a second process locks the resource
  51. tsl, and then a third process needs to block, waiting for the resource
  52. tsl, when the second process wants to wake up the third process, it can't
  53. because it's not the holder of the lock!  For the second process to be
  54. the holder of the lock, we would have to make a system call per
  55. uncontested lock, which is what we were trying to get away from in the
  56. first place.
  57. There are some hybrid schemes, such as signaling the holder of the lock,
  58. or using a different blocking offset depending on which process is
  59. holding the lock, but it gets complicated fairly quickly.  I'm open to
  60. suggestions, but I'm not holding my breath.
  61. Regardless, we use this form of locking when HAVE_SPINLOCKS is not
  62. defined, (i.e. we're locking in the kernel) because it doesn't have the
  63. limitations found in System V semaphores, and because the normal state of
  64. the kernel object in that case is unlocked, so the process releasing the
  65. lock is also the holder of the lock.
  66. The System V semaphore design has a number of other limitations that make
  67. it inappropriate for this task.  Namely:
  68. First, the semaphore key name space is separate from the file system name
  69. space (although there exist methods for using file names to create
  70. semaphore keys).  If we use a well-known key, there's no reason to believe
  71. that any particular key will not already be in use, either by another
  72. instance of the DB application or some other application, in which case
  73. the DB application will fail.  If we create a key, then we have to use a
  74. file system name to rendezvous and pass around the key.
  75. Second, System V semaphores traditionally have compile-time, system-wide
  76. limits on the number of semaphore keys that you can have.  Typically, that
  77. number is far too low for any practical purpose.  Since the semaphores
  78. permit more than a single slot per semaphore key, we could try and get
  79. around that limit by using multiple slots, but that means that the file
  80. that we're using for rendezvous is going to have to contain slot
  81. information as well as semaphore key information, and we're going to be
  82. reading/writing it on every db_mutex_t init or destroy operation.  Anyhow,
  83. similar compile-time, system-wide limits on the numbers of slots per
  84. semaphore key kick in, and you're right back where you started.
  85. My fantasy is that once POSIX.1 standard mutexes are in wide-spread use,
  86. we can switch to them.  My guess is that it won't happen, because the
  87. POSIX semaphores are only required to work for threads within a process,
  88. and not independent processes.
  89. Note: there are races in the statistics code, but since it's just that,
  90. I didn't bother fixing them.  (The fix requires a mutex tsl, so, when/if
  91. this code is fixed to do rational locking (see above), then change the
  92. statistics update code to acquire/release the mutex tsl.