blob: d1a6ec2e0a344b644d946384b2be93ee60944f76 [file] [log] [blame]
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define C_LUCY_SHAREDLOCK
#include "Lucy/Util/ToolSet.h"
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
#include "Lucy/Store/SharedLock.h"
#include "Lucy/Store/DirHandle.h"
#include "Lucy/Store/Folder.h"
#include "Lucy/Store/OutStream.h"
SharedLock*
ShLock_new(Folder *folder, const CharBuf *name, const CharBuf *host,
int32_t timeout, int32_t interval) {
SharedLock *self = (SharedLock*)VTable_Make_Obj(SHAREDLOCK);
return ShLock_init(self, folder, name, host, timeout, interval);
}
SharedLock*
ShLock_init(SharedLock *self, Folder *folder, const CharBuf *name,
const CharBuf *host, int32_t timeout, int32_t interval) {
LFLock_init((LockFileLock*)self, folder, name, host, timeout, interval);
// Override.
DECREF(self->lock_path);
self->lock_path = (CharBuf*)INCREF(&EMPTY);
return self;
}
bool_t
ShLock_shared(SharedLock *self) {
UNUSED_VAR(self);
return true;
}
bool_t
ShLock_request(SharedLock *self) {
uint32_t i = 0;
ShLock_request_t super_request
= (ShLock_request_t)SUPER_METHOD(SHAREDLOCK, ShLock, Request);
// EMPTY lock_path indicates whether this particular instance is locked.
if (self->lock_path != (CharBuf*)&EMPTY
&& Folder_Exists(self->folder, self->lock_path)
) {
// Don't allow double obtain.
Err_set_error((Err*)LockErr_new(CB_newf("Lock already obtained via '%o'",
self->lock_path)));
return false;
}
DECREF(self->lock_path);
self->lock_path = CB_new(CB_Get_Size(self->name) + 10);
do {
CB_setf(self->lock_path, "locks/%o-%u32.lock", self->name, ++i);
} while (Folder_Exists(self->folder, self->lock_path));
bool_t success = super_request(self);
if (!success) { ERR_ADD_FRAME(Err_get_error()); }
return success;
}
void
ShLock_release(SharedLock *self) {
if (self->lock_path != (CharBuf*)&EMPTY) {
ShLock_release_t super_release
= (ShLock_release_t)SUPER_METHOD(SHAREDLOCK, ShLock, Release);
super_release(self);
// Empty out lock_path.
DECREF(self->lock_path);
self->lock_path = (CharBuf*)INCREF(&EMPTY);
}
}
void
ShLock_clear_stale(SharedLock *self) {
DirHandle *dh;
CharBuf *entry;
CharBuf *candidate = NULL;
CharBuf *lock_dir_name = (CharBuf*)ZCB_WRAP_STR("locks", 5);
if (Folder_Find_Folder(self->folder, lock_dir_name)) {
dh = Folder_Open_Dir(self->folder, lock_dir_name);
if (!dh) { RETHROW(INCREF(Err_get_error())); }
entry = DH_Get_Entry(dh);
}
else {
return;
}
// Take a stab at any file that begins with our lock name.
while (DH_Next(dh)) {
if (CB_Starts_With(entry, self->name)
&& CB_Ends_With_Str(entry, ".lock", 5)
) {
candidate = candidate ? candidate : CB_new(0);
CB_setf(candidate, "%o/%o", lock_dir_name, entry);
ShLock_Maybe_Delete_File(self, candidate, false, true);
}
}
DECREF(candidate);
DECREF(dh);
}
bool_t
ShLock_is_locked(SharedLock *self) {
DirHandle *dh;
CharBuf *entry;
CharBuf *lock_dir_name = (CharBuf*)ZCB_WRAP_STR("locks", 5);
if (Folder_Find_Folder(self->folder, lock_dir_name)) {
dh = Folder_Open_Dir(self->folder, lock_dir_name);
if (!dh) { RETHROW(INCREF(Err_get_error())); }
entry = DH_Get_Entry(dh);
}
else {
return false;
}
while (DH_Next(dh)) {
// Translation: $locked = 1 if $entry =~ /^\Q$name-\d+\.lock$/
if (CB_Starts_With(entry, self->name)
&& CB_Ends_With_Str(entry, ".lock", 5)
) {
ZombieCharBuf *scratch = ZCB_WRAP(entry);
ZCB_Chop(scratch, sizeof(".lock") - 1);
while (isdigit(ZCB_Code_Point_From(scratch, 1))) {
ZCB_Chop(scratch, 1);
}
if (ZCB_Code_Point_From(scratch, 1) == '-') {
ZCB_Chop(scratch, 1);
if (ZCB_Equals(scratch, (Obj*)self->name)) {
DECREF(dh);
return true;
}
}
}
}
DECREF(dh);
return false;
}