a simple url shortening service, in the same vein as bit.ly and tinyurl.com, written in Go and using BoltDB as a backend
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

89 lines
1.9KB

  1. package bbolt
  2. import (
  3. "fmt"
  4. "syscall"
  5. "time"
  6. "unsafe"
  7. "golang.org/x/sys/unix"
  8. )
  9. // flock acquires an advisory lock on a file descriptor.
  10. func flock(db *DB, exclusive bool, timeout time.Duration) error {
  11. var t time.Time
  12. if timeout != 0 {
  13. t = time.Now()
  14. }
  15. fd := db.file.Fd()
  16. var lockType int16
  17. if exclusive {
  18. lockType = syscall.F_WRLCK
  19. } else {
  20. lockType = syscall.F_RDLCK
  21. }
  22. for {
  23. // Attempt to obtain an exclusive lock.
  24. lock := syscall.Flock_t{Type: lockType}
  25. err := syscall.FcntlFlock(fd, syscall.F_SETLK, &lock)
  26. if err == nil {
  27. return nil
  28. } else if err != syscall.EAGAIN {
  29. return err
  30. }
  31. // If we timed out then return an error.
  32. if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout {
  33. return ErrTimeout
  34. }
  35. // Wait for a bit and try again.
  36. time.Sleep(flockRetryTimeout)
  37. }
  38. }
  39. // funlock releases an advisory lock on a file descriptor.
  40. func funlock(db *DB) error {
  41. var lock syscall.Flock_t
  42. lock.Start = 0
  43. lock.Len = 0
  44. lock.Type = syscall.F_UNLCK
  45. lock.Whence = 0
  46. return syscall.FcntlFlock(uintptr(db.file.Fd()), syscall.F_SETLK, &lock)
  47. }
  48. // mmap memory maps a DB's data file.
  49. func mmap(db *DB, sz int) error {
  50. // Map the data file to memory.
  51. b, err := unix.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED|db.MmapFlags)
  52. if err != nil {
  53. return err
  54. }
  55. // Advise the kernel that the mmap is accessed randomly.
  56. if err := unix.Madvise(b, syscall.MADV_RANDOM); err != nil {
  57. return fmt.Errorf("madvise: %s", err)
  58. }
  59. // Save the original byte slice and convert to a byte array pointer.
  60. db.dataref = b
  61. db.data = (*[maxMapSize]byte)(unsafe.Pointer(&b[0]))
  62. db.datasz = sz
  63. return nil
  64. }
  65. // munmap unmaps a DB's data file from memory.
  66. func munmap(db *DB) error {
  67. // Ignore the unmap if we have no mapped data.
  68. if db.dataref == nil {
  69. return nil
  70. }
  71. // Unmap using the original byte slice.
  72. err := unix.Munmap(db.dataref)
  73. db.dataref = nil
  74. db.data = nil
  75. db.datasz = 0
  76. return err
  77. }