L
- The type of the Logger
to be created.T
- The type of the Record
instances managed by the
Logger
.P
- The type of the Column
's value used for partitioning the
Logger
.public abstract class AbstractPartedLogger<L extends Logger<T>,T,P extends T> extends Object implements Logger<T>
PartedLoggerImpl
is a partitioning logger
which encapsulates Logger
instances or
CompositeLoggerImpl
instances (or sub-classes of
it) representing partitions.
This means: A partition is regarded to be a dedicated physical data sink or a
CompositeLoggerImpl
containing
Logger
instances attached to physical data sinks.
A physical data sink may be a database (SQL or NoSQL), a files-system or
volatile memory (in memory). To be more concrete: A physical data sink may be
a domain when using Amazon's SimpleDB, it may be a database table when using
MySQL, it may be a HashMap or a List when using in memory storage.
The Record
instances as managed by the
Logger
instances are mapped to the fields of the
physical data sink (e.g. table columns regarding databases).
The Record
instances are stored to, retrieved
from or deleted from dedicated partitions depending on partitioning
Criteria
contained in the
Record
instances (or the query
Criteria
instances). The
Criteria
(e.g. the column partition
Criteria
in a
Record
) as provided to the #log(Record) method
is used by the PartedLoggerImpl
to select the
partition to be addressed. In case of query operations the query
Criteria
is used to determine the targeted
partition.
(in case no partition can be determined and a fallback logger has been configured, then data may get logged to the fallback logger)
In practice there can be several (composite) logger instances being the
partitions of the PartedLoggerImpl
, each
individually addressed by the partitioning
Criteria
.
This approach a) helps us scale horizontally per partition when using
CompositeLoggerImpl
instances per partition and
b) helps limiting the traffic on those horizontally scaling (composite)
logger instances by partitioning the data per
Criteria
using the parted logger (or its
sub-classes): Partitioning simply means switching to the partition defined by
the Criteria
to perform the according logger
operation.
Not having the PartedLoggerImpl
(or a sub-class
of it) would cause all the traffic for all
Criteria
to hit just a single (composite)
Logger
, limiting the possibility to scale
endlessly (this one logger would be the bottleneck, even when being massively
scaled horizontally): In particular this applies when looking at the extended
versions of the PartedLoggerImpl
such as the
PartedQueryLoggerImpl
and the
PartedTrimLoggerImpl
where query requests are
passed only to the partition which contains the required data: Increasing
query traffic is parted and does not hit increasingly a single (composite)
logger.
A Record
to be assigned to a partition must
provide a column, the so called partition column, whose value is used to
determine which partition is to be addressed. The partition identifying
column is passed upon construction to this
PartedLoggerImpl
. Specializations may hide this
parameter from their constructors and pass their partitioning column from
inside their constructor to the super constructor.
The PartedQueryLoggerImpl
extends the
PartedLoggerImpl
with the functionality of a
query logger. Any query operations, such as #findLogs(Criteria), are targeted
at that partition containing the queried data. For this to work, the query
must obey some rules:
The query is to contain an EqualWithCriteria
addressing the partition in an unambiguous way; by being part of a root level
AndCriteria
or an unambiguously nested
AndCriteria
hierarchy. More than one partition
gets detected when unambiguous OrCriteria
are
applied to the partition criteria. In such cases, the query is addressed to
the potential partitions.
In case it was not possible to identify any partitions, then as a fallback, all partitions are queried.
Query results are taken from from the invoked partitions (in normal cases
this would be a single partition) round robin. the first result is taken from
the first queried partition's result set (
Record
s), the next result from the next queried
partition and so on to start over again with the first queried partition.
Round robin has been used to prevent invalidation of physical data sinks's
result sets as of timeouts.
The PartedTrimLoggerImpl
extends the parted query
logger with the functionality of a trim logger. Delete operations with a
query such as #deleteLogs(Criteria) are applied to the partitions in the same
manner as done for #findLogs(Criteria).
PartedLoggerImpl
Modifier and Type | Field and Description |
---|---|
protected static RuntimeLogger |
LOGGER |
Constructor and Description |
---|
AbstractPartedLogger(org.refcodes.tabular.Column<P> aPartitionColumn,
LoggerFactory<L> aLoggerFactory,
boolean isPartitionAutoInitialize)
Constructs the
AbstractPartedLogger , a partitioning
Logger . |
AbstractPartedLogger(org.refcodes.tabular.Column<P> aPartitionColumn,
String aFallbackLoggerName,
LoggerFactory<L> aLoggerFactory,
boolean isPartitionAutoInitialize)
Same as
#AbstractPartedLogger(Column, LoggerToRuntimeLoggerFactory, boolean)
with the difference that a fallback Logger is being supported
when no partition can be determined for an operation |
Modifier and Type | Method and Description |
---|---|
void |
decomposePartition(P aPartition)
Decomposes the given partition.
|
void |
destroyPartition(P aPartition)
Destroys the given partition.
|
void |
flushPartition(P aPartition)
Flushes the given partition, all buffered data is to be forwarded to the
physical data sink.
|
protected L |
getFallbackLogger()
Returns the fallback
Logger . |
protected Collection<L> |
getLoggers()
Provides access to the partitions managed by the
AbstractPartedLogger . |
protected org.refcodes.tabular.Column<P> |
getPartitionColumn()
Provides access to the
Column used to identify partitions. |
protected L |
getPartitionLogger(P aPartition)
Returns the
Logger being responsible for the given partition. |
protected String |
getPartitionUid(P aPartition)
Depending whether the partition object provides a universal ID or not we
return the string representation of the partition's object or the UID.
|
boolean |
hasPartition(P aPartition)
Tests whether the provided partition exists.
|
L |
initPartition(P aPartition)
Initializes the given partition.
|
void |
log(org.refcodes.tabular.Record<? extends T> aRecord)
Logs a
Record . |
protected static RuntimeLogger LOGGER
public AbstractPartedLogger(org.refcodes.tabular.Column<P> aPartitionColumn, LoggerFactory<L> aLoggerFactory, boolean isPartitionAutoInitialize)
AbstractPartedLogger
, a partitioning
Logger
. A LoggerFactory
is used to create
the (composite) Logger
instances representing the dedicated
partitions. This is achieved by the method
#initPartition(UniversalIdStorage)
. The type of the
Logger
instance being created depends on the provided
LoggerFactory
.
We may provide a LoggerFactory
producing plain
simple Logger
instances or more complex
CompositeLoggerImpl
instances or even PartedLoggerImpl
instances.
Partitions may get automatically created when enabling the partition auto
initialize option. When logging a Record
(via the method
log(Record)
) whose partitioning Column
addresses a non
existing partition, then the LoggerFactory
us used
to create that partition on the fly.
This option does not regard the find or delete methods. In case no
partition criteria was provided or determined, then a fallback
Logger
may be used for logging such data to.
The provided Column
specifies a Record
's Column
holding the value being used to choose the partition from. Extensions of
the AbstractPartedLogger
use this partition Column
to
determine an addressed partition from a query Criteria
.aPartitionColumn
- Defines the Column
identifying a
partition.aLoggerFactory
- The LoggerFactory
to be used
when creating partitions.isPartitionAutoInitialize
- True in case a partition not yet
existing is to be created on the fly, e.g. in case a log is
applied against a non existing partition, then the
initPartition(Object)
method is invoked upon this
partition. Find and delete operations are not considered.public AbstractPartedLogger(org.refcodes.tabular.Column<P> aPartitionColumn, String aFallbackLoggerName, LoggerFactory<L> aLoggerFactory, boolean isPartitionAutoInitialize)
#AbstractPartedLogger(Column, LoggerToRuntimeLoggerFactory, boolean)
with the difference that a fallback Logger
is being supported
when no partition can be determined for an operationaPartitionColumn
- Defines the Column
identifying a
partition.aFallbackLoggerName
- In case a fallback Logger
is to be
used when no partition can be determined, then this parameter
defines the name of the fallback Logger
.aLoggerFactory
- The LoggerFactory
to be used
when creating partitions.isPartitionAutoInitialize
- True in case a partition not yet
existing is to be created on the fly, e.g. in case a log is
applied against a non existing partition, then the
initPartition(Object)
method is invoked upon this
partition. Find and delete operations are not considered.public void log(org.refcodes.tabular.Record<? extends T> aRecord) throws IllegalRecordRuntimeException, UnexpectedLogRuntimeException
Logger
Record
. The targeted data sink for the Record
instances (where them are physically stored) depends on the
implementation of the Logger
. It can be a console, a file, a
stream or a database.log
in interface Logger<T>
aRecord
- The Record
to be logged.IllegalRecordRuntimeException
- Thrown in case the record cannot be
logged as a specific implementation might expect some dedicated
Column
instances to be contained in the provided Record.UnexpectedLogRuntimeException
- Thrown in case some other problems
regarding logging occurred, e.g. the data sink (physical system
where to log to) experiences problems.public boolean hasPartition(P aPartition)
aPartition
- The value of the Column
in a Record
specifying the partition which is to be addressed (or even auto
initialized).public L initPartition(P aPartition) throws org.refcodes.component.InitializeException
aPartition
- The value of the Column
in a Record
specifying the partition which is to be auto initialized.org.refcodes.component.InitializeException
- in case initialization failed e.g. when the
partition already exists or the system was not able to create the
required amount of endpoints.public void destroyPartition(P aPartition)
@param
- aPartition The partition to be destroyed.public void flushPartition(P aPartition) throws IOException
aPartition
- The partition to be flushed.IOException
- in case there were problems when flushing, e.g.
there is none such partition.public void decomposePartition(P aPartition)
aPartition
- The partition to be decomposed.protected Collection<L> getLoggers()
AbstractPartedLogger
. This is especially useful for extensions of
this class such as the AbstractPartedQueryLogger
or the
AbstractPartedTrimLogger
.Logger
instances managed by the
AbstractPartedLogger
instance.protected String getPartitionUid(P aPartition)
aPartition
- The partition for which to get the identifierprotected org.refcodes.tabular.Column<P> getPartitionColumn()
Column
used to identify partitions.Column
identifying partitions.protected L getPartitionLogger(P aPartition)
Logger
being responsible for the given partition.Copyright © 2016. All rights reserved.