use of org.apache.pulsar.metadata.api.Notification in project pulsar by apache.
the class LocalMemoryMetadataStore method storeDelete.
@Override
public CompletableFuture<Void> storeDelete(String path, Optional<Long> optExpectedVersion) {
if (!isValidPath(path)) {
return FutureUtil.failedFuture(new MetadataStoreException.InvalidPathException(path));
}
synchronized (map) {
CompletableFuture<Void> future = new CompletableFuture<>();
Value value = map.get(path);
if (value == null) {
execute(() -> future.completeExceptionally(new NotFoundException("")), future);
} else if (optExpectedVersion.isPresent() && optExpectedVersion.get() != value.version) {
execute(() -> future.completeExceptionally(new BadVersionException("")), future);
} else {
map.remove(path);
receivedNotification(new Notification(NotificationType.Deleted, path));
notifyParentChildrenChanged(path);
execute(() -> future.complete(null), future);
}
return future;
}
}
use of org.apache.pulsar.metadata.api.Notification in project pulsar by apache.
the class LocalMemoryMetadataStore method storePut.
@Override
public CompletableFuture<Stat> storePut(String path, byte[] data, Optional<Long> optExpectedVersion, EnumSet<CreateOption> options) {
if (!isValidPath(path)) {
return FutureUtil.failedFuture(new MetadataStoreException.InvalidPathException(path));
}
synchronized (map) {
boolean hasVersion = optExpectedVersion.isPresent();
int expectedVersion = optExpectedVersion.orElse(-1L).intValue();
if (options.contains(CreateOption.Sequential)) {
path += Long.toString(sequentialIdGenerator.getAndIncrement());
}
long now = System.currentTimeMillis();
CompletableFuture<Stat> future = new CompletableFuture<>();
if (hasVersion && expectedVersion == -1) {
Value newValue = new Value(0, data, now, now, options.contains(CreateOption.Ephemeral));
Value existingValue = map.putIfAbsent(path, newValue);
if (existingValue != null) {
execute(() -> future.completeExceptionally(new BadVersionException("")), future);
} else {
receivedNotification(new Notification(NotificationType.Created, path));
notifyParentChildrenChanged(path);
String finalPath = path;
execute(() -> future.complete(new Stat(finalPath, 0, now, now, newValue.isEphemeral(), true)), future);
}
} else {
Value existingValue = map.get(path);
long existingVersion = existingValue != null ? existingValue.version : -1;
if (hasVersion && expectedVersion != existingVersion) {
execute(() -> future.completeExceptionally(new BadVersionException("")), future);
} else {
long newVersion = existingValue != null ? existingValue.version + 1 : 0;
long createdTimestamp = existingValue != null ? existingValue.createdTimestamp : now;
Value newValue = new Value(newVersion, data, createdTimestamp, now, options.contains(CreateOption.Ephemeral));
map.put(path, newValue);
NotificationType type = existingValue == null ? NotificationType.Created : NotificationType.Modified;
receivedNotification(new Notification(type, path));
if (type == NotificationType.Created) {
notifyParentChildrenChanged(path);
}
String finalPath = path;
execute(() -> future.complete(new Stat(finalPath, newValue.version, newValue.createdTimestamp, newValue.modifiedTimestamp, false, true)), future);
}
}
return future;
}
}
use of org.apache.pulsar.metadata.api.Notification in project pulsar by apache.
the class EtcdMetadataStore method handleWatchResponse.
private void handleWatchResponse(WatchResponse watchResponse) {
watchResponse.getEvents().forEach(we -> {
String path = we.getKeyValue().getKey().toString(StandardCharsets.UTF_8);
if (we.getEventType() == WatchEvent.EventType.PUT) {
if (we.getKeyValue().getVersion() == 1) {
receivedNotification(new Notification(NotificationType.Created, path));
notifyParentChildrenChanged(path);
} else {
receivedNotification(new Notification(NotificationType.Modified, path));
}
} else if (we.getEventType() == WatchEvent.EventType.DELETE) {
receivedNotification(new Notification(NotificationType.Deleted, path));
notifyParentChildrenChanged(path);
}
});
}
use of org.apache.pulsar.metadata.api.Notification in project pulsar by apache.
the class MetadataStoreTest method notificationListeners.
@Test(dataProvider = "impl")
public void notificationListeners(String provider, Supplier<String> urlSupplier) throws Exception {
@Cleanup MetadataStore store = MetadataStoreFactory.create(urlSupplier.get(), MetadataStoreConfig.builder().build());
BlockingQueue<Notification> notifications = new LinkedBlockingDeque<>();
store.registerListener(n -> {
notifications.add(n);
});
String key1 = newKey();
assertFalse(store.get(key1).join().isPresent());
// Trigger created notification
Stat stat = store.put(key1, "value-1".getBytes(), Optional.empty()).join();
assertTrue(store.get(key1).join().isPresent());
assertEquals(store.getChildren(key1).join(), Collections.emptyList());
assertEquals(stat.getVersion(), 0);
Notification n = notifications.poll(3, TimeUnit.SECONDS);
assertNotNull(n);
assertEquals(n.getType(), NotificationType.Created);
assertEquals(n.getPath(), key1);
// Trigger modified notification
stat = store.put(key1, "value-2".getBytes(), Optional.empty()).join();
n = notifications.poll(3, TimeUnit.SECONDS);
assertNotNull(n);
assertEquals(n.getType(), NotificationType.Modified);
assertEquals(n.getPath(), key1);
assertEquals(stat.getVersion(), 1);
// Trigger modified notification on the parent
String key1Child = key1 + "/xx";
assertFalse(store.get(key1Child).join().isPresent());
store.put(key1Child, "value-2".getBytes(), Optional.empty()).join();
n = notifications.poll(3, TimeUnit.SECONDS);
assertNotNull(n);
assertEquals(n.getType(), NotificationType.Created);
assertEquals(n.getPath(), key1Child);
n = notifications.poll(3, TimeUnit.SECONDS);
assertNotNull(n);
assertEquals(n.getType(), NotificationType.ChildrenChanged);
assertEquals(n.getPath(), key1);
assertTrue(store.exists(key1Child).join());
assertEquals(store.getChildren(key1).join(), Collections.singletonList("xx"));
store.delete(key1Child, Optional.empty()).join();
n = notifications.poll(3, TimeUnit.SECONDS);
assertNotNull(n);
assertEquals(n.getType(), NotificationType.Deleted);
assertEquals(n.getPath(), key1Child);
// Parent should be notified of the deletion
n = notifications.poll(3, TimeUnit.SECONDS);
assertNotNull(n);
assertEquals(n.getType(), NotificationType.ChildrenChanged);
assertEquals(n.getPath(), key1);
}
use of org.apache.pulsar.metadata.api.Notification in project pulsar by apache.
the class ModularLoadManagerImplTest method testLoadShedding.
// Test that load shedding works
@Test
public void testLoadShedding() throws Exception {
final NamespaceBundleStats stats1 = new NamespaceBundleStats();
final NamespaceBundleStats stats2 = new NamespaceBundleStats();
stats1.msgRateIn = 100;
stats2.msgRateIn = 200;
final Map<String, NamespaceBundleStats> statsMap = new ConcurrentHashMap<>();
statsMap.put(mockBundleName(1), stats1);
statsMap.put(mockBundleName(2), stats2);
final LocalBrokerData localBrokerData = new LocalBrokerData();
localBrokerData.update(new SystemResourceUsage(), statsMap);
final Namespaces namespacesSpy1 = spy(pulsar1.getAdminClient().namespaces());
AtomicReference<String> bundleReference = new AtomicReference<>();
doAnswer(invocation -> {
bundleReference.set(invocation.getArguments()[0].toString() + '/' + invocation.getArguments()[1]);
return null;
}).when(namespacesSpy1).unloadNamespaceBundle(Mockito.anyString(), Mockito.anyString());
setField(pulsar1.getAdminClient(), "namespaces", namespacesSpy1);
pulsar1.getConfiguration().setLoadBalancerEnabled(true);
final LoadData loadData = (LoadData) getField(primaryLoadManager, "loadData");
final Map<String, BrokerData> brokerDataMap = loadData.getBrokerData();
final BrokerData brokerDataSpy1 = spy(brokerDataMap.get(primaryHost));
when(brokerDataSpy1.getLocalData()).thenReturn(localBrokerData);
brokerDataMap.put(primaryHost, brokerDataSpy1);
// Need to update all the bundle data for the shredder to see the spy.
primaryLoadManager.handleDataNotification(new Notification(NotificationType.Created, LoadManager.LOADBALANCE_BROKERS_ROOT + "/broker:8080"));
Thread.sleep(100);
localBrokerData.setCpu(new ResourceUsage(80, 100));
primaryLoadManager.doLoadShedding();
// 80% is below overload threshold: verify nothing is unloaded.
verify(namespacesSpy1, Mockito.times(0)).unloadNamespaceBundle(Mockito.anyString(), Mockito.anyString());
localBrokerData.setCpu(new ResourceUsage(90, 100));
primaryLoadManager.doLoadShedding();
// Most expensive bundle will be unloaded.
verify(namespacesSpy1, Mockito.times(1)).unloadNamespaceBundle(Mockito.anyString(), Mockito.anyString());
assertEquals(bundleReference.get(), mockBundleName(2));
primaryLoadManager.doLoadShedding();
// Now less expensive bundle will be unloaded (normally other bundle would move off and nothing would be
// unloaded, but this is not the case due to the spy's behavior).
verify(namespacesSpy1, Mockito.times(2)).unloadNamespaceBundle(Mockito.anyString(), Mockito.anyString());
assertEquals(bundleReference.get(), mockBundleName(1));
primaryLoadManager.doLoadShedding();
// Now both are in grace period: neither should be unloaded.
verify(namespacesSpy1, Mockito.times(2)).unloadNamespaceBundle(Mockito.anyString(), Mockito.anyString());
}
Aggregations