class LockingNodeUniqueIndexSeek {

    public static <CURSOR extends NodeValueIndexCursor> long apply( Locks.Client locks,
                                                                    LockTracer lockTracer,
                                                                    Supplier<CURSOR> cursors,
                                                                    UniqueNodeIndexSeeker<CURSOR> nodeIndexSeeker,
                                                                    Read read,
                                                                    IndexReference index,
                                                                    IndexQuery.ExactPredicate... predicates )
            throws IndexNotApplicableKernelException, IndexNotFoundKernelException
    {
        int[] entityTokenIds = index.schema().getEntityTokenIds();
        if ( entityTokenIds.length != 1 )
        {
            throw new IndexNotApplicableKernelException( "Multi-token index " + index + " does not support uniqueness." );
        }
        long indexEntryId = indexEntryResourceId( entityTokenIds[0], predicates );

        //First try to find node under a shared lock
        //if not found upgrade to exclusive and try again
        locks.acquireShared( lockTracer, INDEX_ENTRY, indexEntryId );
        try ( CURSOR cursor = cursors.get();
              IndexReaders readers = new IndexReaders( index, read ) )
        {
            nodeIndexSeeker.nodeIndexSeekWithFreshIndexReader( cursor, readers.createReader(), predicates );
            if ( !cursor.next() )
            {
                locks.releaseShared( INDEX_ENTRY, indexEntryId );
                locks.acquireExclusive( lockTracer, INDEX_ENTRY, indexEntryId );
                nodeIndexSeeker.nodeIndexSeekWithFreshIndexReader( cursor, readers.createReader(), predicates );
                if ( cursor.next() ) // we found it under the exclusive lock
                {
                    // downgrade to a shared lock
                    locks.acquireShared( lockTracer, INDEX_ENTRY, indexEntryId );
                    locks.releaseExclusive( INDEX_ENTRY, indexEntryId );
                }
            }

            return cursor.nodeReference();
        }
    }

}