001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2006-2009 Sun Microsystems, Inc.
025 *      Portions Copyright 2014-2015 ForgeRock AS
026 */
027package org.opends.server.loggers;
028import static org.opends.messages.LoggerMessages.*;
029
030import java.io.File;
031import java.util.Arrays;
032import java.util.List;
033
034import org.forgerock.i18n.LocalizableMessage;
035import org.forgerock.i18n.slf4j.LocalizedLogger;
036import org.opends.server.admin.server.ConfigurationChangeListener;
037import org.opends.server.admin.std.server.SizeLimitLogRetentionPolicyCfg;
038import org.opends.server.core.DirectoryServer;
039import org.forgerock.opendj.config.server.ConfigChangeResult;
040import org.opends.server.types.DirectoryException;
041
042/**
043 * This class implements a retention policy based on the amount of
044 * space taken by the log files.
045 */
046public class SizeBasedRetentionPolicy implements
047    RetentionPolicy<SizeLimitLogRetentionPolicyCfg>,
048    ConfigurationChangeListener<SizeLimitLogRetentionPolicyCfg>
049{
050
051  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
052  private static final File[] EMPTY_FILE_LIST = new File[0];
053
054  private long size;
055  private FileComparator comparator;
056  private SizeLimitLogRetentionPolicyCfg config;
057
058  /** {@inheritDoc} */
059  @Override
060  public void initializeLogRetentionPolicy(
061      SizeLimitLogRetentionPolicyCfg config)
062  {
063    this.size = config.getDiskSpaceUsed();
064    this.comparator = new FileComparator();
065    this.config = config;
066
067    config.addSizeLimitChangeListener(this);
068  }
069
070  /** {@inheritDoc} */
071  @Override
072  public boolean isConfigurationChangeAcceptable(
073      SizeLimitLogRetentionPolicyCfg config,
074      List<LocalizableMessage> unacceptableReasons)
075  {
076    // Changes should always be OK
077    return true;
078  }
079
080  /** {@inheritDoc} */
081  @Override
082  public ConfigChangeResult applyConfigurationChange(
083      SizeLimitLogRetentionPolicyCfg config)
084  {
085    this.size = config.getDiskSpaceUsed();
086    this.config = config;
087
088    return new ConfigChangeResult();
089  }
090
091  /** {@inheritDoc} */
092  @Override
093  public File[] deleteFiles(FileNamingPolicy fileNamingPolicy)
094      throws DirectoryException
095  {
096    File[] files = fileNamingPolicy.listFiles();
097    if(files == null)
098    {
099      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
100          ERR_LOGGER_ERROR_LISTING_FILES.get(fileNamingPolicy.getInitialName()));
101    }
102
103    long totalLength = 0;
104    for (File file : files)
105    {
106      totalLength += file.length();
107    }
108
109    logger.trace("Total size of files: %d, Max: %d", totalLength, size);
110
111    if (totalLength <= size)
112    {
113      return EMPTY_FILE_LIST;
114    }
115
116    long freeSpaceNeeded = totalLength - size;
117
118    // Sort files based on last modified time.
119    Arrays.sort(files, comparator);
120
121    long freedSpace = 0;
122    int j;
123    for (j = files.length - 1; j >= 0; j--)
124    {
125      freedSpace += files[j].length();
126      if (freedSpace >= freeSpaceNeeded)
127      {
128        break;
129      }
130    }
131
132    File[] filesToDelete = new File[files.length - j];
133    System.arraycopy(files, j, filesToDelete, 0, filesToDelete.length);
134    return filesToDelete;
135  }
136
137  /** {@inheritDoc} */
138  @Override
139  public String toString()
140  {
141    return "Size Based Retention Policy " + config.dn();
142  }
143}
144