private boolean update()

in core/src/main/java/com/jetbrains/youtrackdb/internal/core/storage/index/sbtree/singlevalue/v3/BTree.java [250:408]


  private boolean update(
      final AtomicOperation atomicOperation,
      final K k,
      final RID rid,
      final IndexEngineValidator<K, RID> validator) {
    return calculateInsideComponentOperation(
        atomicOperation,
        operation -> {
          acquireExclusiveLock();
          try {
            var key = k;
            var value = rid;

            if (key != null) {
              key = keySerializer.preprocess(serializerFactory, key, (Object[]) keyTypes);
              final var serializedKey =
                  keySerializer.serializeNativeAsWhole(serializerFactory, key, (Object[]) keyTypes);
              if (serializedKey.length > MAX_KEY_SIZE) {
                throw new TooBigIndexKeyException(storage.getName(),
                    "Key size is more than allowed, operation was canceled. Current key size "
                        + serializedKey.length
                        + ", allowed  "
                        + MAX_KEY_SIZE, getName());
              }
              var bucketSearchResult =
                  findBucketForUpdate(key, atomicOperation);

              var keyBucketCacheEntry =
                  loadPageForWrite(
                      atomicOperation, fileId, bucketSearchResult.getLastPathItem(), true);
              var keyBucket =
                  new CellBTreeSingleValueBucketV3<K>(keyBucketCacheEntry);
              final byte[] oldRawValue;
              if (bucketSearchResult.getItemIndex() > -1) {
                oldRawValue =
                    keyBucket.getRawValue(bucketSearchResult.getItemIndex(), keySerializer,
                        serializerFactory);
              } else {
                oldRawValue = null;
              }
              final RID oldValue;
              if (oldRawValue == null) {
                oldValue = null;
              } else {
                final int collectionId = ShortSerializer.INSTANCE.deserializeNative(oldRawValue, 0);
                final var collectionPosition =
                    LongSerializer.INSTANCE.deserializeNative(
                        oldRawValue, ShortSerializer.SHORT_SIZE);
                oldValue = new RecordId(collectionId, collectionPosition);
              }

              if (validator != null) {
                var failure = true; // assuming validation throws by default
                var ignored = false;

                try {

                  final var result = validator.validate(key, oldValue, value);
                  if (result == IndexEngineValidator.IGNORE) {
                    ignored = true;
                    failure = false;
                    return false;
                  }

                  value = (RID) result;
                  failure = false;
                } finally {
                  if (failure || ignored) {
                    keyBucketCacheEntry.close();
                  }
                }
              }

              final var serializedValue =
                  new byte[ShortSerializer.SHORT_SIZE + LongSerializer.LONG_SIZE];
              ShortSerializer.INSTANCE.serializeNative(
                  (short) value.getCollectionId(), serializedValue, 0);
              LongSerializer.INSTANCE.serializeNative(
                  value.getCollectionPosition(), serializedValue, ShortSerializer.SHORT_SIZE);

              int insertionIndex;
              final int sizeDiff;
              if (bucketSearchResult.getItemIndex() >= 0) {
                assert oldRawValue != null;

                if (oldRawValue.length == serializedValue.length) {
                  keyBucket.updateValue(
                      bucketSearchResult.getItemIndex(), serializedValue, serializedKey.length);
                  keyBucketCacheEntry.close();
                  return true;
                } else {
                  keyBucket.removeLeafEntry(bucketSearchResult.getItemIndex(), serializedKey);
                  insertionIndex = bucketSearchResult.getItemIndex();
                  sizeDiff = 0;
                }
              } else {
                insertionIndex = -bucketSearchResult.getItemIndex() - 1;
                sizeDiff = 1;
              }

              while (!keyBucket.addLeafEntry(insertionIndex, serializedKey, serializedValue)) {
                bucketSearchResult =
                    splitBucket(
                        keyBucket,
                        keyBucketCacheEntry,
                        bucketSearchResult.getPath(),
                        bucketSearchResult.getInsertionIndexes(),
                        insertionIndex,
                        atomicOperation);

                insertionIndex = bucketSearchResult.getItemIndex();

                final var pageIndex = bucketSearchResult.getLastPathItem();

                if (pageIndex != keyBucketCacheEntry.getPageIndex()) {
                  keyBucketCacheEntry.close();

                  keyBucketCacheEntry = loadPageForWrite(atomicOperation, fileId, pageIndex, true);
                }

                //noinspection ObjectAllocationInLoop
                keyBucket = new CellBTreeSingleValueBucketV3<>(keyBucketCacheEntry);
              }

              keyBucketCacheEntry.close();

              if (sizeDiff != 0) {
                updateSize(sizeDiff, atomicOperation);
              }
            } else {
              var sizeDiff = 0;
              final RID oldValue;
              try (final var cacheEntry =
                  loadPageForWrite(atomicOperation, nullBucketFileId, 0, true)) {
                final var nullBucket =
                    new CellBTreeSingleValueV3NullBucket(cacheEntry);
                oldValue = nullBucket.getValue();

                if (validator != null) {
                  final var result = validator.validate(null, oldValue, value);
                  if (result == IndexEngineValidator.IGNORE) {
                    return false;
                  }
                }

                if (oldValue != null) {
                  sizeDiff = -1;
                }
                nullBucket.setValue(value);
              }
              sizeDiff++;
              updateSize(sizeDiff, atomicOperation);
            }
            return true;
          } finally {
            releaseExclusiveLock();
          }
        });
  }