/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using IndexFileNameFilter = Lucene.Net.Index.IndexFileNameFilter;
namespace Lucene.Net.Store
{
/// A Directory is a flat list of files. Files may be written once, when they
/// are created. Once a file is created it may only be opened for read, or
/// deleted. Random access is permitted both when reading and writing.
///
/// Java's i/o APIs not used directly, but rather all i/o is
/// through this API. This permits things such as:
/// - implementation of RAM-based indices;
/// - implementation indices stored in a database, via JDBC;
/// - implementation of an index as a single file;
///
///
/// Directory locking is implemented by an instance of
///, and can be changed for each Directory
/// instance using .
///
///
[Serializable]
public abstract class Directory : System.IDisposable
{
protected internal volatile bool isOpen = true;
/// Holds the LockFactory instance (implements locking for
/// this Directory instance).
///
[NonSerialized]
protected internal LockFactory interalLockFactory;
/// Returns an array of strings, one for each file in the directory.
///
public abstract System.String[] ListAll();
/// Returns true iff a file with the given name exists.
public abstract bool FileExists(System.String name);
/// Returns the time the named file was last modified.
public abstract long FileModified(System.String name);
/// Set the modified time of an existing file to now.
public abstract void TouchFile(System.String name);
/// Removes an existing file in the directory.
public abstract void DeleteFile(System.String name);
/// Returns the length of a file in the directory.
public abstract long FileLength(System.String name);
/// Creates a new, empty file in the directory with the given name.
/// Returns a stream writing this file.
///
public abstract IndexOutput CreateOutput(System.String name);
/// Ensure that any writes to this file are moved to
/// stable storage. Lucene uses this to properly commit
/// changes to the index, to prevent a machine/OS crash
/// from corrupting the index.
///
public virtual void Sync(System.String name)
{
}
/// Returns a stream reading an existing file.
public abstract IndexInput OpenInput(System.String name);
/// Returns a stream reading an existing file, with the
/// specified read buffer size. The particular Directory
/// implementation may ignore the buffer size. Currently
/// the only Directory implementations that respect this
/// parameter are and
///.
///
public virtual IndexInput OpenInput(System.String name, int bufferSize)
{
return OpenInput(name);
}
/// Construct a .
/// the name of the lock file
///
public virtual Lock MakeLock(System.String name)
{
return interalLockFactory.MakeLock(name);
}
/// Attempt to clear (forcefully unlock and remove) the
/// specified lock. Only call this at a time when you are
/// certain this lock is no longer in use.
///
/// name of the lock to be cleared.
///
public virtual void ClearLock(System.String name)
{
if (interalLockFactory != null)
{
interalLockFactory.ClearLock(name);
}
}
[Obsolete("Use Dispose() instead")]
public void Close()
{
Dispose();
}
/// Closes the store.
public void Dispose()
{
Dispose(true);
}
protected abstract void Dispose(bool disposing);
/// Set the LockFactory that this Directory instance should
/// use for its locking implementation. Each * instance of
/// LockFactory should only be used for one directory (ie,
/// do not share a single instance across multiple
/// Directories).
///
///
/// instance of .
///
public virtual void SetLockFactory(LockFactory lockFactory)
{
System.Diagnostics.Debug.Assert(lockFactory != null);
this.interalLockFactory = lockFactory;
lockFactory.LockPrefix = this.GetLockId();
}
/// Get the LockFactory that this Directory instance is
/// using for its locking implementation. Note that this
/// may be null for Directory implementations that provide
/// their own locking implementation.
///
public virtual LockFactory LockFactory
{
get { return this.interalLockFactory; }
}
/// Return a string identifier that uniquely differentiates
/// this Directory instance from other Directory instances.
/// This ID should be the same if two Directory instances
/// (even in different JVMs and/or on different machines)
/// are considered "the same index". This is how locking
/// "scopes" to the right index.
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
public virtual string GetLockId()
{
return ToString();
}
public override string ToString()
{
return base.ToString() + " lockFactory=" + LockFactory;
}
/// Copy contents of a directory src to a directory dest.
/// If a file in src already exists in dest then the
/// one in dest will be blindly overwritten.
///
/// NOTE: the source directory cannot change
/// while this method is running. Otherwise the results
/// are undefined and you could easily hit a
/// FileNotFoundException.
///
/// NOTE: this method only copies files that look
/// like index files (ie, have extensions matching the
/// known extensions of index files).
///
///
/// source directory
///
/// destination directory
///
/// if true, call method on source directory
///
/// IOException
public static void Copy(Directory src, Directory dest, bool closeDirSrc)
{
System.String[] files = src.ListAll();
IndexFileNameFilter filter = IndexFileNameFilter.Filter;
byte[] buf = new byte[BufferedIndexOutput.BUFFER_SIZE];
for (int i = 0; i < files.Length; i++)
{
if (!filter.Accept(null, files[i]))
continue;
IndexOutput os = null;
IndexInput is_Renamed = null;
try
{
// create file in dest directory
os = dest.CreateOutput(files[i]);
// read current file
is_Renamed = src.OpenInput(files[i]);
// and copy to dest directory
long len = is_Renamed.Length();
long readCount = 0;
while (readCount < len)
{
int toRead = readCount + BufferedIndexOutput.BUFFER_SIZE > len?(int) (len - readCount):BufferedIndexOutput.BUFFER_SIZE;
is_Renamed.ReadBytes(buf, 0, toRead);
os.WriteBytes(buf, toRead);
readCount += toRead;
}
}
finally
{
// graceful cleanup
try
{
if (os != null)
os.Close();
}
finally
{
if (is_Renamed != null)
is_Renamed.Close();
}
}
}
if (closeDirSrc)
src.Close();
}
/// AlreadyClosedException if this Directory is closed
public /*protected internal*/ void EnsureOpen()
{
if (!isOpen)
throw new AlreadyClosedException("this Directory is closed");
}
public bool isOpen_ForNUnit
{
get { return isOpen; }
}
}
}