class StorageBasedLockProvider implements ExtensibleLockProvider {
    private final StorageAccessor storageAccessor;
    private final LockRecordRegistry lockRecordRegistry = new LockRecordRegistry();

    protected StorageBasedLockProvider(StorageAccessor storageAccessor) {
        this.storageAccessor = storageAccessor;
    }

    /** Clears cache of existing lock records. */
    public void clearCache() {
        lockRecordRegistry.clear();
    }

    @Override
    public Optional<SimpleLock> lock(LockConfiguration lockConfiguration) {
        boolean lockObtained = doLock(lockConfiguration);
        if (lockObtained) {
            return Optional.of(new StorageLock(lockConfiguration, storageAccessor));
        } else {
            return Optional.empty();
        }
    }

    /**
     * Sets lockUntil according to LockConfiguration if current lockUntil &lt;= now
     */
    protected boolean doLock(LockConfiguration lockConfiguration) {<FILL_FUNCTION_BODY>}

    private static class StorageLock extends AbstractSimpleLock {
        private final StorageAccessor storageAccessor;

        StorageLock(LockConfiguration lockConfiguration, StorageAccessor storageAccessor) {
            super(lockConfiguration);
            this.storageAccessor = storageAccessor;
        }

        @Override
        public void doUnlock() {
            storageAccessor.unlock(lockConfiguration);
        }

        @Override
        public Optional<SimpleLock> doExtend(LockConfiguration newConfig) {
            if (storageAccessor.extend(newConfig)) {
                return Optional.of(new StorageLock(newConfig, storageAccessor));
            } else {
                return Optional.empty();
            }
        }
    }
}

        String name = lockConfiguration.getName();

        boolean tryToCreateLockRecord = !lockRecordRegistry.lockRecordRecentlyCreated(name);
        if (tryToCreateLockRecord) {
            // create record in case it does not exist yet
            if (storageAccessor.insertRecord(lockConfiguration)) {
                lockRecordRegistry.addLockRecord(name);
                // we were able to create the record, we have the lock
                return true;
            }
            // we were not able to create the record, it already exists, let's put it to the
            // cache so we
            // do not try again
            lockRecordRegistry.addLockRecord(name);
        }

        // let's try to update the record, if successful, we have the lock
        try {
            return storageAccessor.updateRecord(lockConfiguration);
        } catch (Exception e) {
            // There are some users that start the app before they have the DB ready.
            // If they use JDBC, insertRecord returns false, the record is stored in the
            // recordRegistry
            // and the insert is not attempted again. We are assuming that the DB still does
            // not exist
            // when update is attempted. Unlike insert, update throws the exception, and we
            // clear the
            // cache here.
            if (tryToCreateLockRecord) {
                lockRecordRegistry.removeLockRecord(name);
            }
            throw e;
        }
    
<no_super_class>