int alock_close ( alock_info_t * info, int nosave ) { alock_slot_t slot_data; int res; if ( !info->al_slot ) return ALOCK_CLEAN; (void) memset ((void *) &slot_data, 0, sizeof(alock_slot_t)); res = alock_grab_lock (info->al_fd, 0); if (res == -1) { fail: /* Windows doesn't clean up locks immediately when a process exits. * Make sure we release our locks, to prevent stale locks from * hanging around. */ alock_release_lock (info->al_fd, 0); close (info->al_fd); return ALOCK_UNSTABLE; } /* mark our slot as clean */ res = alock_read_slot (info, &slot_data); if (res == -1) { if (slot_data.al_appname != NULL) ber_memfree (slot_data.al_appname); goto fail; } slot_data.al_lock = ALOCK_UNLOCKED; if ( nosave ) slot_data.al_lock |= ALOCK_NOSAVE; /* since we have slot 0 locked, we don't need our slot lock */ res = alock_release_lock (info->al_fd, info->al_slot); if (res == -1) { goto fail; } res = alock_write_slot (info, &slot_data); if (res == -1) { if (slot_data.al_appname != NULL) ber_memfree (slot_data.al_appname); goto fail; } if (slot_data.al_appname != NULL) { ber_memfree (slot_data.al_appname); slot_data.al_appname = NULL; } res = alock_release_lock (info->al_fd, 0); if (res == -1) { close (info->al_fd); return ALOCK_UNSTABLE; } res = close (info->al_fd); if (res == -1) return ALOCK_UNSTABLE; return ALOCK_CLEAN; }
int alock_close ( alock_info_t * info, int nosave ) { alock_slot_t slot_data; int res; if ( !info->al_slot ) return ALOCK_CLEAN; (void) memset ((void *) &slot_data, 0, sizeof(alock_slot_t)); res = alock_grab_lock (info->al_fd, 0); if (res == -1) { close (info->al_fd); return ALOCK_UNSTABLE; } /* mark our slot as clean */ res = alock_read_slot (info, &slot_data); if (res == -1) { close (info->al_fd); if (slot_data.al_appname != NULL) ber_memfree (slot_data.al_appname); return ALOCK_UNSTABLE; } slot_data.al_lock = ALOCK_UNLOCKED; if ( nosave ) slot_data.al_lock |= ALOCK_NOSAVE; res = alock_write_slot (info, &slot_data); if (res == -1) { close (info->al_fd); if (slot_data.al_appname != NULL) ber_memfree (slot_data.al_appname); return ALOCK_UNSTABLE; } if (slot_data.al_appname != NULL) { ber_memfree (slot_data.al_appname); slot_data.al_appname = NULL; } res = alock_release_lock (info->al_fd, info->al_slot); if (res == -1) { close (info->al_fd); return ALOCK_UNSTABLE; } res = alock_release_lock (info->al_fd, 0); if (res == -1) { close (info->al_fd); return ALOCK_UNSTABLE; } res = close (info->al_fd); if (res == -1) return ALOCK_UNSTABLE; return ALOCK_CLEAN; }
int alock_recover ( alock_info_t * info ) { struct stat statbuf; alock_slot_t slot_data; alock_info_t scan_info; int res, max_slot; assert (info != NULL); scan_info.al_fd = info->al_fd; (void) memset ((void *) &slot_data, 0, sizeof(alock_slot_t)); res = alock_grab_lock (info->al_fd, 0); if (res == -1) { goto fail; } res = fstat (info->al_fd, &statbuf); if (res == -1) { goto fail; } max_slot = (statbuf.st_size + ALOCK_SLOT_SIZE - 1) / ALOCK_SLOT_SIZE; for (scan_info.al_slot = 1; scan_info.al_slot < max_slot; ++ scan_info.al_slot) { if (scan_info.al_slot != info->al_slot) { res = alock_query_slot (&scan_info) & ~ALOCK_NOSAVE; if (res == ALOCK_LOCKED || res == ALOCK_UNIQUE) { /* recovery attempt on an active db? */ goto fail; } else if (res == ALOCK_DIRTY) { /* mark it clean */ res = alock_read_slot (&scan_info, &slot_data); if (res == -1) { goto fail; } slot_data.al_lock = ALOCK_UNLOCKED; res = alock_write_slot (&scan_info, &slot_data); if (res == -1) { if (slot_data.al_appname != NULL) ber_memfree (slot_data.al_appname); goto fail; } if (slot_data.al_appname != NULL) { ber_memfree (slot_data.al_appname); slot_data.al_appname = NULL; } } else if (res == -1) { goto fail; } } } res = alock_release_lock (info->al_fd, 0); if (res == -1) { close (info->al_fd); return ALOCK_UNSTABLE; } return ALOCK_CLEAN; fail: alock_release_lock (info->al_fd, 0); close (info->al_fd); return ALOCK_UNSTABLE; }
int alock_scan ( alock_info_t * info ) { struct stat statbuf; alock_info_t scan_info; int res, max_slot; int dirty_count, live_count, nosave; assert (info != NULL); scan_info.al_fd = info->al_fd; res = alock_grab_lock (info->al_fd, 0); if (res == -1) { close (info->al_fd); return ALOCK_UNSTABLE; } res = fstat (info->al_fd, &statbuf); if (res == -1) { close (info->al_fd); return ALOCK_UNSTABLE; } max_slot = (statbuf.st_size + ALOCK_SLOT_SIZE - 1) / ALOCK_SLOT_SIZE; dirty_count = 0; live_count = 0; nosave = 0; for (scan_info.al_slot = 1; scan_info.al_slot < max_slot; ++ scan_info.al_slot) { if (scan_info.al_slot != info->al_slot) { res = alock_query_slot (&scan_info); if (res & ALOCK_NOSAVE) { nosave = ALOCK_NOSAVE; res ^= ALOCK_NOSAVE; } if (res == ALOCK_LOCKED) { ++live_count; } else if (res == ALOCK_DIRTY) { ++dirty_count; } else if (res == -1) { close (info->al_fd); return ALOCK_UNSTABLE; } } } res = alock_release_lock (info->al_fd, 0); if (res == -1) { close (info->al_fd); return ALOCK_UNSTABLE; } if (dirty_count) { if (live_count) { close (info->al_fd); return ALOCK_UNSTABLE; } else { return ALOCK_RECOVER | nosave; } } return ALOCK_CLEAN | nosave; }
int alock_open ( alock_info_t * info, const char * appname, const char * envdir, int locktype ) { struct stat statbuf; alock_info_t scan_info; alock_slot_t slot_data; char * filename; int res, max_slot; int dirty_count, live_count, nosave; char *ptr; assert (info != NULL); assert (appname != NULL); assert (envdir != NULL); assert ((locktype & ALOCK_SMASK) >= 1 && (locktype & ALOCK_SMASK) <= 2); slot_data.al_lock = locktype; slot_data.al_stamp = time(NULL); slot_data.al_pid = getpid(); slot_data.al_appname = ber_memcalloc (1, ALOCK_MAX_APPNAME); if (slot_data.al_appname == NULL) { return ALOCK_UNSTABLE; } strncpy (slot_data.al_appname, appname, ALOCK_MAX_APPNAME-1); slot_data.al_appname [ALOCK_MAX_APPNAME-1] = '\0'; filename = ber_memcalloc (1, strlen (envdir) + strlen ("/alock") + 1); if (filename == NULL ) { ber_memfree (slot_data.al_appname); return ALOCK_UNSTABLE; } ptr = lutil_strcopy(filename, envdir); lutil_strcopy(ptr, "/alock"); #ifdef _WIN32 { HANDLE handle = CreateFile (filename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); info->al_fd = _open_osfhandle (handle, 0); } #else info->al_fd = open (filename, O_CREAT|O_RDWR, 0666); #endif ber_memfree (filename); if (info->al_fd < 0) { ber_memfree (slot_data.al_appname); return ALOCK_UNSTABLE; } info->al_slot = 0; res = alock_grab_lock (info->al_fd, 0); if (res == -1) { close (info->al_fd); ber_memfree (slot_data.al_appname); return ALOCK_UNSTABLE; } res = fstat (info->al_fd, &statbuf); if (res == -1) { close (info->al_fd); ber_memfree (slot_data.al_appname); return ALOCK_UNSTABLE; } max_slot = (statbuf.st_size + ALOCK_SLOT_SIZE - 1) / ALOCK_SLOT_SIZE; dirty_count = 0; live_count = 0; nosave = 0; scan_info.al_fd = info->al_fd; for (scan_info.al_slot = 1; scan_info.al_slot < max_slot; ++ scan_info.al_slot) { if (scan_info.al_slot != info->al_slot) { res = alock_query_slot (&scan_info); if (res & ALOCK_NOSAVE) { nosave = ALOCK_NOSAVE; res ^= ALOCK_NOSAVE; } if (res == ALOCK_UNLOCKED && info->al_slot == 0) { info->al_slot = scan_info.al_slot; } else if (res == ALOCK_LOCKED) { ++live_count; } else if (res == ALOCK_UNIQUE && (( locktype & ALOCK_SMASK ) == ALOCK_UNIQUE || nosave )) { close (info->al_fd); ber_memfree (slot_data.al_appname); return ALOCK_BUSY; } else if (res == ALOCK_DIRTY) { ++dirty_count; } else if (res == -1) { close (info->al_fd); ber_memfree (slot_data.al_appname); return ALOCK_UNSTABLE; } } } if (dirty_count && live_count) { close (info->al_fd); ber_memfree (slot_data.al_appname); return ALOCK_UNSTABLE; } if (info->al_slot == 0) info->al_slot = max_slot + 1; res = alock_grab_lock (info->al_fd, info->al_slot); if (res == -1) { close (info->al_fd); ber_memfree (slot_data.al_appname); return ALOCK_UNSTABLE; } res = alock_write_slot (info, &slot_data); ber_memfree (slot_data.al_appname); if (res == -1) { close (info->al_fd); return ALOCK_UNSTABLE; } alock_share_lock (info->al_fd, info->al_slot); res = alock_release_lock (info->al_fd, 0); if (res == -1) { close (info->al_fd); return ALOCK_UNSTABLE; } if (dirty_count) return ALOCK_RECOVER | nosave; return ALOCK_CLEAN | nosave; }