public class HelixAccountService
extends java.lang.Object
implements com.github.ambry.account.AccountService
An implementation of AccountService
that employs a HelixPropertyStore
as its underlying storage.
It's in the middle of transitioning from using old helix path to the new path. In old way, it internally stores
the full set of Account
metadata in a store-relative path defined in LegacyMetadataStore
. In the
new way, it internally stores the list of blob ids that point to different versions of Account
metadata.
In both way, the latest full Account
metadata will be cached locally, so serving an Account
query
will not incur any calls to remote ZooKeeper
or AmbryServer
.
After transition, this implementation would not only save the latest set of Account
metadata, but also save
several previous versions. It keeps a list of blob ids in HelixPropertyStore
and remove the earliest one
when it reaches the limit of the version numbers. There are several benefits from this approach.
Account
metadata
When a HelixAccountService
starts up, it will automatically fetch a full set of Account
metadata
and store them in its local cache. It also takes a Notifier
, and subscribes to a ACCOUNT_METADATA_CHANGE_TOPIC
.
Each time when receiving a FULL_ACCOUNT_METADATA_CHANGE_MESSAGE
, it will fetch the updated full
Account
metadata, and refresh its local cache. After every successful operation for updating a collection of
Account
s, it publishes a FULL_ACCOUNT_METADATA_CHANGE_MESSAGE
for ACCOUNT_METADATA_CHANGE_TOPIC
through the Notifier
. If the remote Account
metadata is corrupted or has conflict, HelixAccountService
will not update its local cache.
The full set of the Account
metadata are stored in a single ZNRecord
or a single blob in the new way, as a
simple map from a string account id to the Account
content in json as a string.
Limited by HelixPropertyStore
, the total size of Account
data stored on a single ZNRecord
cannot exceed 1MB before the transition.
Modifier and Type | Field and Description |
---|---|
protected java.util.concurrent.atomic.AtomicReference<com.github.ambry.account.AccountInfoMap> |
accountInfoMapRef |
protected AccountServiceMetrics |
accountServiceMetrics |
protected java.util.concurrent.locks.ReentrantLock |
lock |
protected java.util.concurrent.atomic.AtomicBoolean |
open |
Modifier and Type | Method and Description |
---|---|
boolean |
addAccountUpdateConsumer(java.util.function.Consumer<java.util.Collection<com.github.ambry.account.Account>> accountUpdateConsumer) |
protected void |
checkOpen()
Ensures the account service is ready to process requests.
|
void |
close() |
com.github.ambry.account.Account |
getAccountById(short id) |
com.github.ambry.account.Account |
getAccountByName(java.lang.String accountName) |
java.util.Collection<com.github.ambry.account.Account> |
getAllAccounts() |
protected void |
notifyAccountUpdateConsumers(com.github.ambry.account.AccountInfoMap newAccountInfoMap,
com.github.ambry.account.AccountInfoMap oldAccountInfoMap,
boolean isCalledFromListener)
Logs and notifies account update
Consumer s about any new account changes/creations. |
boolean |
removeAccountUpdateConsumer(java.util.function.Consumer<java.util.Collection<com.github.ambry.account.Account>> accountUpdateConsumer) |
void |
setupRouter(com.github.ambry.router.Router router)
set the router to the given one.
|
boolean |
updateAccounts(java.util.Collection<com.github.ambry.account.Account> accounts) |
protected final java.util.concurrent.atomic.AtomicBoolean open
protected final java.util.concurrent.atomic.AtomicReference<com.github.ambry.account.AccountInfoMap> accountInfoMapRef
protected final java.util.concurrent.locks.ReentrantLock lock
protected final AccountServiceMetrics accountServiceMetrics
public void setupRouter(com.github.ambry.router.Router router) throws java.lang.IllegalStateException
Account
metadata from ambry server.router
- The router to set.java.lang.IllegalStateException
- when the router already set up.public boolean updateAccounts(java.util.Collection<com.github.ambry.account.Account> accounts)
This call is blocking until it completes the operation of updating account metadata to HelixPropertyStore
.
There is a slight chance that an Account
could be updated successfully, but its value was
set based on an outdated Account
. This can be fixed after generationId
is introduced
to Account
.
updateAccounts
in interface com.github.ambry.account.AccountService
public void close()
close
in interface java.io.Closeable
close
in interface java.lang.AutoCloseable
protected void checkOpen()
IllegalStateException
) if the account service is not ready to process requests.public com.github.ambry.account.Account getAccountByName(java.lang.String accountName)
getAccountByName
in interface com.github.ambry.account.AccountService
public com.github.ambry.account.Account getAccountById(short id)
getAccountById
in interface com.github.ambry.account.AccountService
public java.util.Collection<com.github.ambry.account.Account> getAllAccounts()
getAllAccounts
in interface com.github.ambry.account.AccountService
public boolean addAccountUpdateConsumer(java.util.function.Consumer<java.util.Collection<com.github.ambry.account.Account>> accountUpdateConsumer)
addAccountUpdateConsumer
in interface com.github.ambry.account.AccountService
public boolean removeAccountUpdateConsumer(java.util.function.Consumer<java.util.Collection<com.github.ambry.account.Account>> accountUpdateConsumer)
removeAccountUpdateConsumer
in interface com.github.ambry.account.AccountService
protected void notifyAccountUpdateConsumers(com.github.ambry.account.AccountInfoMap newAccountInfoMap, com.github.ambry.account.AccountInfoMap oldAccountInfoMap, boolean isCalledFromListener)
Consumer
s about any new account changes/creations.newAccountInfoMap
- the new AccountInfoMap
that has been set.oldAccountInfoMap
- the AccountInfoMap
that was cached before this change.isCalledFromListener
- true
if the caller is the account update listener, otherwise.