static int alock_query_slot ( alock_info_t * info ) { int res, nosave; alock_slot_t slot_data; assert (info != NULL); assert (info->al_slot > 0); (void) memset ((void *) &slot_data, 0, sizeof (alock_slot_t)); alock_read_slot (info, &slot_data); if (slot_data.al_appname != NULL) ber_memfree (slot_data.al_appname); slot_data.al_appname = NULL; nosave = slot_data.al_lock & ALOCK_NOSAVE; if ((slot_data.al_lock & ALOCK_SMASK) == ALOCK_UNLOCKED) return slot_data.al_lock; res = alock_test_lock (info->al_fd, info->al_slot); if (res < 0) return -1; if (res > 0) { if ((slot_data.al_lock & ALOCK_SMASK) == ALOCK_UNIQUE) { return slot_data.al_lock; } else { return ALOCK_LOCKED | nosave; } } return ALOCK_DIRTY | nosave; }
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; }